From 7dbab35d361ec8046ec957f656019879d2f7424b Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 11:45:08 +0200 Subject: [PATCH 01/41] Lint + add .clant-format file. --- .clang-format | 20 + src/blake256.c | 361 ++- src/blake256.h | 10 +- src/btchip.c | 58 +- src/btchip_apdu_get_coin_version.c | 38 +- src/btchip_apdu_get_firmware_version.c | 46 +- src/btchip_apdu_get_trusted_input.c | 68 +- src/btchip_apdu_get_wallet_public_key.c | 104 +- src/btchip_apdu_hash_input_finalize_full.c | 366 ++- src/btchip_apdu_hash_input_start.c | 53 +- src/btchip_apdu_hash_sign.c | 70 +- src/btchip_apdu_sign_message.c | 176 +- src/btchip_bagl_extensions.h | 32 +- src/btchip_base58.c | 219 +- src/btchip_bcd.c | 43 +- src/btchip_context.c | 65 +- src/btchip_ecc.c | 30 +- src/btchip_helpers.c | 216 +- src/btchip_internal.h | 30 +- src/btchip_nvram.c | 30 +- src/btchip_public_ram_key_variables.c | 30 +- src/btchip_public_ram_key_variables.h | 30 +- src/btchip_public_ram_variables.c | 30 +- src/btchip_public_ram_variables.h | 30 +- src/btchip_rom_variables.c | 118 +- src/btchip_rom_variables.h | 30 +- src/btchip_secure_value.c | 38 +- src/btchip_transaction.c | 927 +++--- src/btchip_transaction.h | 48 +- src/main.c | 3019 ++++++++++++-------- 30 files changed, 3443 insertions(+), 2892 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b4abfa0 --- /dev/null +++ b/.clang-format @@ -0,0 +1,20 @@ +--- +BasedOnStyle: Google +IndentWidth: 4 +--- +Language: Cpp +ColumnLimit: 100 +PointerAlignment: Right +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true +AllowAllParametersOfDeclarationOnNextLine: false +SortIncludes: false +SpaceAfterCStyleCast: true +AllowShortCaseLabelsOnASingleLine: false +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortFunctionsOnASingleLine: None +BinPackArguments: false +BinPackParameters: false +--- diff --git a/src/blake256.c b/src/blake256.c index 9b4678e..62b90b9 100644 --- a/src/blake256.c +++ b/src/blake256.c @@ -14,205 +14,204 @@ #include -#define U8TO32_BIG(p) \ - (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ - ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) - -#define U32TO8_BIG(p, v) \ - (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ - (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); - -static const uint8_t sigma[][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, - {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, - {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, - {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } -}; - -static const uint32_t u256[16] = { - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917 -}; +#define U8TO32_BIG(p) \ + (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | ((uint32_t)((p)[2]) << 8) | \ + ((uint32_t)((p)[3]))) + +#define U32TO8_BIG(p, v) \ + (p)[0] = (uint8_t)((v) >> 24); \ + (p)[1] = (uint8_t)((v) >> 16); \ + (p)[2] = (uint8_t)((v) >> 8); \ + (p)[3] = (uint8_t)((v)); + +static const uint8_t sigma[][16] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}}; + +static const uint32_t u256[16] = {0x243f6a88, + 0x85a308d3, + 0x13198a2e, + 0x03707344, + 0xa4093822, + 0x299f31d0, + 0x082efa98, + 0xec4e6c89, + 0x452821e6, + 0x38d01377, + 0xbe5466cf, + 0x34e90c6c, + 0xc0ac29b7, + 0xc97c50dd, + 0x3f84d5b5, + 0xb5470917}; static const uint8_t padding[129] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static void blake256_compress( BLAKE256_CTX *S, const uint8_t *block ) { - uint32_t v[16], m[16], i; -#define ROT(x,n) (((x)<<(32-n))|( (x)>>(n))) -#define G(a,b,c,d,e) \ - v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e+1]]) + v[b]; \ - v[d] = ROT( v[d] ^ v[a],16); \ - v[c] += v[d]; \ - v[b] = ROT( v[b] ^ v[c],12); \ - v[a] += (m[sigma[i][e+1]] ^ u256[sigma[i][e]])+v[b]; \ - v[d] = ROT( v[d] ^ v[a], 8); \ - v[c] += v[d]; \ - v[b] = ROT( v[b] ^ v[c], 7); - - for( i = 0; i < 16; ++i ) m[i] = U8TO32_BIG( block + i * 4 ); - - for( i = 0; i < 8; ++i ) v[i] = S->h[i]; - - v[ 8] = S->s[0] ^ u256[0]; - v[ 9] = S->s[1] ^ u256[1]; - v[10] = S->s[2] ^ u256[2]; - v[11] = S->s[3] ^ u256[3]; - v[12] = u256[4]; - v[13] = u256[5]; - v[14] = u256[6]; - v[15] = u256[7]; - - /* don't xor t when the block is only padding */ - if ( !S->nullt ) { - v[12] ^= S->t[0]; - v[13] ^= S->t[0]; - v[14] ^= S->t[1]; - v[15] ^= S->t[1]; - } - - for( i = 0; i < 14; ++i ) { - /* column step */ - G( 0, 4, 8, 12, 0 ); - G( 1, 5, 9, 13, 2 ); - G( 2, 6, 10, 14, 4 ); - G( 3, 7, 11, 15, 6 ); - /* diagonal step */ - G( 0, 5, 10, 15, 8 ); - G( 1, 6, 11, 12, 10 ); - G( 2, 7, 8, 13, 12 ); - G( 3, 4, 9, 14, 14 ); - } - - for( i = 0; i < 16; ++i ) S->h[i % 8] ^= v[i]; - - for( i = 0; i < 8 ; ++i ) S->h[i] ^= S->s[i % 4]; -} + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static void blake256_compress(BLAKE256_CTX *S, const uint8_t *block) { + uint32_t v[16], m[16], i; +#define ROT(x, n) (((x) << (32 - n)) | ((x) >> (n))) +#define G(a, b, c, d, e) \ + v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e + 1]]) + v[b]; \ + v[d] = ROT(v[d] ^ v[a], 16); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c], 12); \ + v[a] += (m[sigma[i][e + 1]] ^ u256[sigma[i][e]]) + v[b]; \ + v[d] = ROT(v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT(v[b] ^ v[c], 7); + + for (i = 0; i < 16; ++i) m[i] = U8TO32_BIG(block + i * 4); + + for (i = 0; i < 8; ++i) v[i] = S->h[i]; + + v[8] = S->s[0] ^ u256[0]; + v[9] = S->s[1] ^ u256[1]; + v[10] = S->s[2] ^ u256[2]; + v[11] = S->s[3] ^ u256[3]; + v[12] = u256[4]; + v[13] = u256[5]; + v[14] = u256[6]; + v[15] = u256[7]; + + /* don't xor t when the block is only padding */ + if (!S->nullt) { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for (i = 0; i < 14; ++i) { + /* column step */ + G(0, 4, 8, 12, 0); + G(1, 5, 9, 13, 2); + G(2, 6, 10, 14, 4); + G(3, 7, 11, 15, 6); + /* diagonal step */ + G(0, 5, 10, 15, 8); + G(1, 6, 11, 12, 10); + G(2, 7, 8, 13, 12); + G(3, 4, 9, 14, 14); + } + for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i]; -void blake256_Init( BLAKE256_CTX *S ) { - S->h[0] = 0x6a09e667; - S->h[1] = 0xbb67ae85; - S->h[2] = 0x3c6ef372; - S->h[3] = 0xa54ff53a; - S->h[4] = 0x510e527f; - S->h[5] = 0x9b05688c; - S->h[6] = 0x1f83d9ab; - S->h[7] = 0x5be0cd19; - S->t[0] = S->t[1] = S->buflen = S->nullt = 0; - S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; + for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4]; } +void blake256_Init(BLAKE256_CTX *S) { + S->h[0] = 0x6a09e667; + S->h[1] = 0xbb67ae85; + S->h[2] = 0x3c6ef372; + S->h[3] = 0xa54ff53a; + S->h[4] = 0x510e527f; + S->h[5] = 0x9b05688c; + S->h[6] = 0x1f83d9ab; + S->h[7] = 0x5be0cd19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} -void blake256_Update( BLAKE256_CTX *S, const uint8_t *in, size_t inlen ) { - size_t left = S->buflen; - size_t fill = 64 - left; +void blake256_Update(BLAKE256_CTX *S, const uint8_t *in, size_t inlen) { + size_t left = S->buflen; + size_t fill = 64 - left; - /* data left and data received fill a block */ - if( left && ( inlen >= fill ) ) { - memcpy( ( void * ) ( S->buf + left ), ( void * ) in, fill ); - S->t[0] += 512; + /* data left and data received fill a block */ + if (left && (inlen >= fill)) { + memcpy((void *) (S->buf + left), (void *) in, fill); + S->t[0] += 512; - if ( S->t[0] == 0 ) S->t[1]++; + if (S->t[0] == 0) S->t[1]++; - blake256_compress( S, S->buf ); - in += fill; - inlen -= fill; - left = 0; - } + blake256_compress(S, S->buf); + in += fill; + inlen -= fill; + left = 0; + } - /* compress blocks of data received */ - while( inlen >= 64 ) { - S->t[0] += 512; + /* compress blocks of data received */ + while (inlen >= 64) { + S->t[0] += 512; - if ( S->t[0] == 0 ) S->t[1]++; + if (S->t[0] == 0) S->t[1]++; - blake256_compress( S, in ); - in += 64; - inlen -= 64; - } + blake256_compress(S, in); + in += 64; + inlen -= 64; + } - /* store any data left */ - if( inlen > 0 ) { - memcpy( ( void * ) ( S->buf + left ), \ - ( void * ) in, ( size_t ) inlen ); - S->buflen = left + ( int )inlen; - } - else S->buflen = 0; + /* store any data left */ + if (inlen > 0) { + memcpy((void *) (S->buf + left), (void *) in, (size_t) inlen); + S->buflen = left + (int) inlen; + } else + S->buflen = 0; } - -void blake256_Final( BLAKE256_CTX *S, uint8_t *out ) { - uint8_t msglen[8], zo = 0x01, oo = 0x81; - uint32_t lo = S->t[0] + ( S->buflen << 3 ), hi = S->t[1]; - - /* support for hashing more than 2^32 bits */ - if ( lo < ( S->buflen << 3 ) ) hi++; - - U32TO8_BIG( msglen + 0, hi ); - U32TO8_BIG( msglen + 4, lo ); - - if ( S->buflen == 55 ) /* one padding byte */ { - S->t[0] -= 8; - blake256_Update( S, &oo, 1 ); - } - else { - if ( S->buflen < 55 ) /* enough space to fill the block */ { - if ( !S->buflen ) S->nullt = 1; - - S->t[0] -= 440 - ( S->buflen << 3 ); - blake256_Update( S, padding, 55 - S->buflen ); - } - else /* need 2 compressions */ { - S->t[0] -= 512 - ( S->buflen << 3 ); - blake256_Update( S, padding, 64 - S->buflen ); - S->t[0] -= 440; - blake256_Update( S, padding + 1, 55 ); - S->nullt = 1; +void blake256_Final(BLAKE256_CTX *S, uint8_t *out) { + uint8_t msglen[8], zo = 0x01, oo = 0x81; + uint32_t lo = S->t[0] + (S->buflen << 3), hi = S->t[1]; + + /* support for hashing more than 2^32 bits */ + if (lo < (S->buflen << 3)) hi++; + + U32TO8_BIG(msglen + 0, hi); + U32TO8_BIG(msglen + 4, lo); + + if (S->buflen == 55) /* one padding byte */ { + S->t[0] -= 8; + blake256_Update(S, &oo, 1); + } else { + if (S->buflen < 55) /* enough space to fill the block */ { + if (!S->buflen) S->nullt = 1; + + S->t[0] -= 440 - (S->buflen << 3); + blake256_Update(S, padding, 55 - S->buflen); + } else /* need 2 compressions */ { + S->t[0] -= 512 - (S->buflen << 3); + blake256_Update(S, padding, 64 - S->buflen); + S->t[0] -= 440; + blake256_Update(S, padding + 1, 55); + S->nullt = 1; + } + + blake256_Update(S, &zo, 1); + S->t[0] -= 8; } - blake256_Update( S, &zo, 1 ); - S->t[0] -= 8; - } - - S->t[0] -= 64; - blake256_Update( S, msglen, 8 ); - U32TO8_BIG( out + 0, S->h[0] ); - U32TO8_BIG( out + 4, S->h[1] ); - U32TO8_BIG( out + 8, S->h[2] ); - U32TO8_BIG( out + 12, S->h[3] ); - U32TO8_BIG( out + 16, S->h[4] ); - U32TO8_BIG( out + 20, S->h[5] ); - U32TO8_BIG( out + 24, S->h[6] ); - U32TO8_BIG( out + 28, S->h[7] ); + S->t[0] -= 64; + blake256_Update(S, msglen, 8); + U32TO8_BIG(out + 0, S->h[0]); + U32TO8_BIG(out + 4, S->h[1]); + U32TO8_BIG(out + 8, S->h[2]); + U32TO8_BIG(out + 12, S->h[3]); + U32TO8_BIG(out + 16, S->h[4]); + U32TO8_BIG(out + 20, S->h[5]); + U32TO8_BIG(out + 24, S->h[6]); + U32TO8_BIG(out + 28, S->h[7]); } - -void blake256( const uint8_t *in, size_t inlen, uint8_t *out ) { - BLAKE256_CTX S; - blake256_Init( &S ); - blake256_Update( &S, in, inlen ); - blake256_Final( &S, out ); +void blake256(const uint8_t *in, size_t inlen, uint8_t *out) { + BLAKE256_CTX S; + blake256_Init(&S); + blake256_Update(&S, in, inlen); + blake256_Final(&S, out); } diff --git a/src/blake256.h b/src/blake256.h index 1a1a2da..631963f 100644 --- a/src/blake256.h +++ b/src/blake256.h @@ -38,11 +38,11 @@ #define BLAKE256_BLOCK_LENGTH 64 typedef struct { - uint32_t h[8], s[4], t[2]; - size_t buflen; - uint8_t nullt; - uint8_t buf[64]; - uint8_t header; + uint32_t h[8], s[4], t[2]; + size_t buflen; + uint8_t nullt; + uint8_t buf[64]; + uint8_t header; } BLAKE256_CTX; void blake256_Init(BLAKE256_CTX *); diff --git a/src/btchip.c b/src/btchip.c index f3b980e..be29262 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "os.h" @@ -46,8 +46,7 @@ void app_dispatch(void) { cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; ins = G_io_apdu_buffer[ISO_OFFSET_INS]; for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { - if ((cla == DISPATCHER_CLA[dispatched]) && - (ins == DISPATCHER_INS[dispatched])) { + if ((cla == DISPATCHER_CLA[dispatched]) && (ins == DISPATCHER_INS[dispatched])) { break; } } @@ -56,8 +55,7 @@ void app_dispatch(void) { goto sendSW; } if (DISPATCHER_DATA_IN[dispatched]) { - if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || - btchip_context_D.inLength - 5 == 0) { + if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || btchip_context_D.inLength - 5 == 0) { btchip_context_D.sw = BTCHIP_SW_INCORRECT_LENGTH; goto sendSW; } @@ -65,21 +63,19 @@ void app_dispatch(void) { // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); } // call the apdu handler - btchip_context_D.sw = ((apduProcessingFunction)PIC( - DISPATCHER_FUNCTIONS[dispatched]))(); + btchip_context_D.sw = + ((apduProcessingFunction) PIC(DISPATCHER_FUNCTIONS[dispatched]))(); // an APDU has been replied. request for power off time extension from the // common ux #ifdef IO_APP_ACTIVITY IO_APP_ACTIVITY(); -#endif // IO_APP_ACTIVITY +#endif // IO_APP_ACTIVITY sendSW: // prepare SW after replied data - G_io_apdu_buffer[btchip_context_D.outLength] = - (btchip_context_D.sw >> 8); - G_io_apdu_buffer[btchip_context_D.outLength + 1] = - (btchip_context_D.sw & 0xff); + G_io_apdu_buffer[btchip_context_D.outLength] = (btchip_context_D.sw >> 8); + G_io_apdu_buffer[btchip_context_D.outLength + 1] = (btchip_context_D.sw & 0xff); btchip_context_D.outLength += 2; } CATCH(EXCEPTION_IO_RESET) { @@ -99,7 +95,7 @@ void app_dispatch(void) { } void app_main(void) { - os_memset(G_io_apdu_buffer, 0, 255); // paranoia + os_memset(G_io_apdu_buffer, 0, 255); // paranoia // Process the incoming APDUs @@ -107,14 +103,12 @@ void app_main(void) { btchip_context_D.outLength = 0; btchip_context_D.io_flags = 0; for (;;) { - // os_memset(G_io_apdu_buffer, 0, 255); // paranoia // receive the whole apdu using the 7 bytes headers (ledger transport) - btchip_context_D.inLength = - io_exchange(CHANNEL_APDU | btchip_context_D.io_flags, - // use the previous outlength as the reply - btchip_context_D.outLength); + btchip_context_D.inLength = io_exchange(CHANNEL_APDU | btchip_context_D.io_flags, + // use the previous outlength as the reply + btchip_context_D.outLength); app_dispatch(); diff --git a/src/btchip_apdu_get_coin_version.c b/src/btchip_apdu_get_coin_version.c index 9618d19..2113a20 100644 --- a/src/btchip_apdu_get_coin_version.c +++ b/src/btchip_apdu_get_coin_version.c @@ -1,24 +1,24 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -#define P1_VERSION_ONLY 0x00 +#define P1_VERSION_ONLY 0x00 #define P1_VERSION_COINID 0x01 unsigned short btchip_apdu_get_coin_version() { @@ -30,11 +30,11 @@ unsigned short btchip_apdu_get_coin_version() { G_io_apdu_buffer[offset++] = btchip_context_D.payToScriptHashVersion; G_io_apdu_buffer[offset++] = btchip_context_D.coinFamily; G_io_apdu_buffer[offset++] = btchip_context_D.coinIdLength; - os_memmove(G_io_apdu_buffer + offset, btchip_context_D.coinId, - btchip_context_D.coinIdLength); + os_memmove(G_io_apdu_buffer + offset, btchip_context_D.coinId, btchip_context_D.coinIdLength); offset += btchip_context_D.coinIdLength; G_io_apdu_buffer[offset++] = btchip_context_D.shortCoinIdLength; - os_memmove(G_io_apdu_buffer + offset, btchip_context_D.shortCoinId, + os_memmove(G_io_apdu_buffer + offset, + btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); offset += btchip_context_D.shortCoinIdLength; btchip_context_D.outLength = offset; diff --git a/src/btchip_apdu_get_firmware_version.c b/src/btchip_apdu_get_firmware_version.c index 6fc12aa..a75d104 100644 --- a/src/btchip_apdu_get_firmware_version.c +++ b/src/btchip_apdu_get_firmware_version.c @@ -1,31 +1,31 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -#define FEATURES_COMPRESSED_KEYS 0x01 -#define FEATURES_SELF_SCREEN_BUTTONS 0x02 +#define FEATURES_COMPRESSED_KEYS 0x01 +#define FEATURES_SELF_SCREEN_BUTTONS 0x02 #define FEATURES_EXTERNAL_SCREEN_BUTTONS 0x04 -#define FEATURES_NFC 0x08 -#define FEATURES_BLE 0x10 -#define FEATURES_TEE 0x20 +#define FEATURES_NFC 0x08 +#define FEATURES_BLE 0x10 +#define FEATURES_TEE 0x20 -#define MODE_SETUP 0x01 +#define MODE_SETUP 0x01 #define MODE_OPERATION 0x02 #define ARCH_ID 0x30 @@ -43,9 +43,7 @@ void get_firmware_version(unsigned char *buffer) { unsigned short btchip_apdu_get_firmware_version() { G_io_apdu_buffer[0] = - (((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0) - ? 0x00 - : 0x01); + (((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0) ? 0x00 : 0x01); G_io_apdu_buffer[0] |= FEATURES_NFC; G_io_apdu_buffer[0] |= FEATURES_BLE; diff --git a/src/btchip_apdu_get_trusted_input.c b/src/btchip_apdu_get_trusted_input.c index 446184c..ab9e975 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/btchip_apdu_get_trusted_input.c @@ -1,25 +1,25 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 -#define GET_TRUSTED_INPUT_P1_NEXT 0x80 +#define GET_TRUSTED_INPUT_P1_NEXT 0x80 #define TRUSTEDINPUT_SIZE 48 @@ -30,44 +30,39 @@ unsigned short btchip_apdu_get_trusted_input() { cx_sha256_t hash; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize btchip_context_D.transactionTargetInput = btchip_read_u32(G_io_apdu_buffer + ISO_OFFSET_CDATA, 1, 0); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.trustedInputProcessed = 0; btchip_context_D.transactionContext.consumeP2SH = 0; btchip_set_check_internal_structure_integrity(1); dataOffset = 4; btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; - } - else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { + } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { return BTCHIP_SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00) { return BTCHIP_SW_INCORRECT_P1_P2; } - btchip_context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; + btchip_context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; btchip_context_D.transactionDataRemaining = apduLength - dataOffset; transaction_parse(PARSE_MODE_TRUSTED_INPUT); if (btchip_context_D.transactionContext.transactionState == BTCHIP_TRANSACTION_PARSED) { - //unsigned char targetHash[32]; + // unsigned char targetHash[32]; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); if (!btchip_context_D.trustedInputProcessed) { // Output was not found return BTCHIP_SW_INCORRECT_DATA; } - //cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, + // cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, // (unsigned char *)NULL, 0, targetHash); // Otherwise prepare @@ -76,18 +71,21 @@ unsigned short btchip_apdu_get_trusted_input() { G_io_apdu_buffer[1] = 0x00; blake256_Final(&btchip_context_D.transactionHashPrefix, G_io_apdu_buffer + 4); - //cx_hash(&btchip_context_D.transactionHashPrefix, CX_LAST, (unsigned char *)NULL, 0, G_io_apdu_buffer + 4); + // cx_hash(&btchip_context_D.transactionHashPrefix, CX_LAST, (unsigned char *)NULL, 0, + // G_io_apdu_buffer + 4); - btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, - btchip_context_D.transactionTargetInput); + btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, btchip_context_D.transactionTargetInput); os_memmove(G_io_apdu_buffer + 4 + 32 + 4, - btchip_context_D.transactionContext.transactionAmount, 8); + btchip_context_D.transactionContext.transactionAmount, + 8); cx_hmac_sha256(N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), G_io_apdu_buffer, - TRUSTEDINPUT_SIZE, trustedInputSignature, 32); - os_memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, - 8); + sizeof(N_btchip.bkp.trustedinput_key), + G_io_apdu_buffer, + TRUSTEDINPUT_SIZE, + trustedInputSignature, + 32); + os_memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, 8); btchip_context_D.outLength = 0x38; } diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 9c70794..bafa5cf 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -1,27 +1,27 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" -#define P1_NO_DISPLAY 0x00 -#define P1_DISPLAY 0x01 +#define P1_NO_DISPLAY 0x00 +#define P1_DISPLAY 0x01 #define P1_REQUEST_TOKEN 0x02 #define P2_LEGACY 0x00 @@ -34,38 +34,40 @@ unsigned short btchip_apdu_get_wallet_public_key() { uint32_t request_token; unsigned char chainCode[32]; bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY); - bool display_request_token = N_btchip.pubKeyRequestRestriction && (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && G_io_apdu_media == IO_APDU_MEDIA_U2F; - bool require_user_approval = N_btchip.pubKeyRequestRestriction && !(display_request_token || display) && G_io_apdu_media == IO_APDU_MEDIA_U2F; - + bool display_request_token = N_btchip.pubKeyRequestRestriction && + (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && + G_io_apdu_media == IO_APDU_MEDIA_U2F; + bool require_user_approval = N_btchip.pubKeyRequestRestriction && + !(display_request_token || display) && + G_io_apdu_media == IO_APDU_MEDIA_U2F; switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { - case P1_NO_DISPLAY: - case P1_DISPLAY: - case P1_REQUEST_TOKEN: - break; - default: - return BTCHIP_SW_INCORRECT_P1_P2; + case P1_NO_DISPLAY: + case P1_DISPLAY: + case P1_REQUEST_TOKEN: + break; + default: + return BTCHIP_SW_INCORRECT_P1_P2; } switch (G_io_apdu_buffer[ISO_OFFSET_P2]) { - case P2_LEGACY: - break; - default: - return BTCHIP_SW_INCORRECT_P1_P2; + case P2_LEGACY: + break; + default: + return BTCHIP_SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_LC] < 0x01) { return BTCHIP_SW_INCORRECT_LENGTH; } - os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); + os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); - if(display_request_token){ - uint8_t request_token_offset = ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA]*4 + 1; + if (display_request_token) { + uint8_t request_token_offset = + ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA] * 4 + 1; request_token = btchip_read_u32(G_io_apdu_buffer + request_token_offset, true, false); } - if (os_global_pin_is_validated() != BOLOS_UX_OK) { return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; } @@ -81,14 +83,14 @@ unsigned short btchip_apdu_get_wallet_public_key() { keyLength = 33; } - os_memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, - sizeof(btchip_public_key_D.W)); + os_memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, sizeof(btchip_public_key_D.W)); - keyLength = btchip_public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - G_io_apdu_buffer + 67, // OUT - 150, // MAXOUTLEN - btchip_context_D.payToAddressVersion, 0); + keyLength = btchip_public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN + keyLength, // INLEN + G_io_apdu_buffer + 67, // OUT + 150, // MAXOUTLEN + btchip_context_D.payToAddressVersion, + 0); G_io_apdu_buffer[66] = keyLength; PRINTF("Length %d\n", keyLength); @@ -98,8 +100,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { } // output chain code - os_memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, - sizeof(chainCode)); + os_memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, sizeof(chainCode)); btchip_context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); if (display) { @@ -111,10 +112,11 @@ unsigned short btchip_apdu_get_wallet_public_key() { G_io_apdu_buffer[200 + keyLength] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_bagl_display_public_key(keyPath); - } - // If the token requested has already been approved in a previous call, the source is trusted so don't ask for approval again - else if(display_request_token && - (!btchip_context_D.has_valid_token || os_memcmp(&request_token, btchip_context_D.last_token, 4))) { + } + // If the token requested has already been approved in a previous call, the source is trusted so + // don't ask for approval again + else if (display_request_token && (!btchip_context_D.has_valid_token || + os_memcmp(&request_token, btchip_context_D.last_token, 4))) { // disable the has_valid_token flag and store the new token btchip_context_D.has_valid_token = false; os_memcpy(btchip_context_D.last_token, &request_token, 4); @@ -123,8 +125,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { G_io_apdu_buffer[200 + 8] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_bagl_display_token(); - } - else if(require_user_approval) { + } else if (require_user_approval) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_bagl_request_pubkey_approval(); } @@ -136,8 +137,7 @@ void btchip_bagl_user_action_display(unsigned char confirming) { unsigned short sw = BTCHIP_SW_OK; // confirm and finish the apdu exchange //spaghetti if (confirming) { - btchip_context_D.outLength -= - 2; // status was already set by the last call + btchip_context_D.outLength -= 2; // status was already set by the last call } else { sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index e9ee378..474d229 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ // TODO Trustlet, BAGL : process each output separately. // review nvm_write policy @@ -22,11 +22,11 @@ #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" -#define FINALIZE_P1_MORE 0x00 -#define FINALIZE_P1_LAST 0x80 +#define FINALIZE_P1_MORE 0x00 +#define FINALIZE_P1_LAST 0x80 #define FINALIZE_P1_CHANGEINFO 0xFF -#define FLAG_SIGNATURE 0x01 +#define FLAG_SIGNATURE 0x01 #define FLAG_CHANGE_VALIDATED 0x80 extern uint8_t prepare_full_output(uint8_t checkOnly); @@ -34,8 +34,7 @@ extern uint8_t prepare_full_output(uint8_t checkOnly); static void btchip_apdu_hash_input_finalize_full_reset(void) { btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - os_memset(btchip_context_D.totalOutputAmount, 0, - sizeof(btchip_context_D.totalOutputAmount)); + os_memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; btchip_set_check_internal_structure_integrity(1); } @@ -43,7 +42,7 @@ static void btchip_apdu_hash_input_finalize_full_reset(void) { static bool check_output_displayable() { PRINTF("Check if output is displayable\n"); bool displayable = true; - unsigned char amount[8], isOpReturn, isP2sh, j,nullAmount = 1; + unsigned char amount[8], isOpReturn, isP2sh, j, nullAmount = 1; unsigned char isOpCreate, isOpCall; for (j = 0; j < 8; j++) { @@ -55,30 +54,27 @@ static bool check_output_displayable() { if (!nullAmount) { btchip_swap_bytes(amount, btchip_context_D.currentOutput, 8); transaction_amount_add_be(btchip_context_D.totalOutputAmount, - btchip_context_D.totalOutputAmount, amount); + btchip_context_D.totalOutputAmount, + amount); } - isOpReturn = - btchip_output_script_is_op_return(btchip_context_D.currentOutput + 8 + 2); // +2 for script version, decred particularity + isOpReturn = btchip_output_script_is_op_return( + btchip_context_D.currentOutput + 8 + 2); // +2 for script version, decred particularity isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + 8 + 2); - isOpCreate = - btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); - isOpCall = - btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); + isOpCreate = btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); + isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); - if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8 + 2) && - !isP2sh && !(nullAmount && isOpReturn)) { + if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8 + 2) && !isP2sh && + !(nullAmount && isOpReturn)) { PRINTF("Error: Unrecognized input script\n"); THROW(EXCEPTION); } if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { bool changeFound = false; unsigned char addressOffset = - (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (!isP2sh && - os_memcmp(btchip_context_D.currentOutput + 8 + 2 + addressOffset, - btchip_context_D.tmpCtx.output.changeAddress + 1, - 20) == 0) { + (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (!isP2sh && os_memcmp(btchip_context_D.currentOutput + 8 + 2 + addressOffset, + btchip_context_D.tmpCtx.output.changeAddress + 1, + 20) == 0) { changeFound = true; } @@ -100,92 +96,89 @@ static bool handle_output_state() { btchip_context_D.discardSize = 0; bool processed = false; switch (btchip_context_D.outputParsingState) { - case BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS: { - // this is default init state - btchip_context_D.totalOutputs = 0; - if (btchip_context_D.currentOutputOffset < 1) { - break; - } - if (btchip_context_D.currentOutput[0] < 0xFD) { - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_context_D.currentOutput[0]; - discardSize = 1; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } - if (btchip_context_D.currentOutput[0] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 3) { + case BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS: { + // this is default init state + btchip_context_D.totalOutputs = 0; + if (btchip_context_D.currentOutputOffset < 1) { break; } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - (btchip_context_D.currentOutput[2] << 8) | - btchip_context_D.currentOutput[1]; - discardSize = 3; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else if (btchip_context_D.currentOutput[0] == 0xFE) { - if (btchip_context_D.currentOutputOffset < 5) { + if (btchip_context_D.currentOutput[0] < 0xFD) { + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + btchip_context_D.currentOutput[0]; + discardSize = 1; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; break; } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_read_u32(btchip_context_D.currentOutput + 1, 0, 0); - discardSize = 5; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else { - THROW(EXCEPTION); - } - } break; + if (btchip_context_D.currentOutput[0] == 0xFD) { + if (btchip_context_D.currentOutputOffset < 3) { + break; + } + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + (btchip_context_D.currentOutput[2] << 8) | btchip_context_D.currentOutput[1]; + discardSize = 3; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else if (btchip_context_D.currentOutput[0] == 0xFE) { + if (btchip_context_D.currentOutputOffset < 5) { + break; + } + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + btchip_read_u32(btchip_context_D.currentOutput + 1, 0, 0); + discardSize = 5; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else { + THROW(EXCEPTION); + } + } break; - case BTCHIP_OUTPUT_PARSING_OUTPUT: { - PRINTF("BTCHIP_OUTPUT_PARSING_OUTPUT:\n"); + case BTCHIP_OUTPUT_PARSING_OUTPUT: { + PRINTF("BTCHIP_OUTPUT_PARSING_OUTPUT:\n"); - unsigned int scriptSize; - if (btchip_context_D.currentOutputOffset < 9) { - break; - } - if (btchip_context_D.currentOutput[8+2] < 0xFD) { - scriptSize = btchip_context_D.currentOutput[8+2]; - discardSize = 1; - } else if (btchip_context_D.currentOutput[8+2] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 9 + 2) { + unsigned int scriptSize; + if (btchip_context_D.currentOutputOffset < 9) { + break; + } + if (btchip_context_D.currentOutput[8 + 2] < 0xFD) { + scriptSize = btchip_context_D.currentOutput[8 + 2]; + discardSize = 1; + } else if (btchip_context_D.currentOutput[8 + 2] == 0xFD) { + if (btchip_context_D.currentOutputOffset < 9 + 2) { + break; + } + scriptSize = btchip_read_u32(btchip_context_D.currentOutput + 9, 0, 0); + discardSize = 3; + } else { + // Unrealistically large script + THROW(EXCEPTION); + } + if (btchip_context_D.currentOutputOffset < 8 + 2 + discardSize + scriptSize) { + discardSize = 0; break; } - scriptSize = - btchip_read_u32(btchip_context_D.currentOutput + 9, 0, 0); - discardSize = 3; - } else { - // Unrealistically large script - THROW(EXCEPTION); - } - if (btchip_context_D.currentOutputOffset < - 8 + 2 + discardSize + scriptSize) { - discardSize = 0; - break; - } - processed = true; + processed = true; - discardSize += 8 + 2 + scriptSize; + discardSize += 8 + 2 + scriptSize; - if (check_output_displayable()) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; + if (check_output_displayable()) { + btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - // The output can be processed by the UI + // The output can be processed by the UI - btchip_context_D.discardSize = discardSize; - discardSize = 0; - } else { - btchip_context_D.remainingOutputs--; - PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); - } - } break; + btchip_context_D.discardSize = discardSize; + discardSize = 0; + } else { + btchip_context_D.remainingOutputs--; + PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); + } + } break; - default: - THROW(EXCEPTION); + default: + THROW(EXCEPTION); } if (discardSize != 0) { @@ -218,8 +211,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && - (p1 != FINALIZE_P1_CHANGEINFO)) { + if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && (p1 != FINALIZE_P1_CHANGEINFO)) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -246,8 +238,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } - os_memset(transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); + os_memset(transactionSummary, 0, sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { // Called with no change path, abort, should be prevented on // the client side @@ -256,32 +247,30 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( os_memmove(transactionSummary->summarydata.keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); - btchip_private_derive_keypair( - transactionSummary->summarydata.keyPath, 1, NULL); - if (((N_btchip.bkp.config.options & - BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { + btchip_private_derive_keypair(transactionSummary->summarydata.keyPath, 1, NULL); + if (((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { keyLength = 65; } else { btchip_compress_public_key_value(btchip_public_key_D.W); keyLength = 33; } - btchip_public_key_hash160( - btchip_public_key_D.W, // IN - keyLength, // INLEN - transactionSummary->summarydata.changeAddress + 1 // OUT + btchip_public_key_hash160(btchip_public_key_D.W, // IN + keyLength, // INLEN + transactionSummary->summarydata.changeAddress + 1 // OUT ); - os_memmove( - btchip_context_D.tmpCtx.output.changeAddress, - transactionSummary->summarydata.changeAddress, - sizeof(transactionSummary->summarydata.changeAddress)); + os_memmove(btchip_context_D.tmpCtx.output.changeAddress, + transactionSummary->summarydata.changeAddress, + sizeof(transactionSummary->summarydata.changeAddress)); btchip_context_D.tmpCtx.output.changeInitialized = 1; btchip_context_D.tmpCtx.output.changeAccepted = 0; - // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval - if(bip44_derivation_guard(transactionSummary->summarydata.keyPath, true)) { + // if the bip44 change path provided is not canonical or its index are unsual, ask + // for user approval + if (bip44_derivation_guard(transactionSummary->summarydata.keyPath, true)) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_context_D.outputParsingState = BTCHIP_BIP44_CHANGE_PATH_VALIDATION; - btchip_bagl_request_change_path_approval(transactionSummary->summarydata.keyPath); + btchip_bagl_request_change_path_approval( + transactionSummary->summarydata.keyPath); } goto return_OK; @@ -290,10 +279,15 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( // Always update the transaction & authorization hashes with the // given data - PRINTF("Adding to prefix hash:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); - blake256_Update(&btchip_context_D.transactionHashPrefix, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset); - blake256_Update(&btchip_context_D.transactionHashAuthorization, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset); - + PRINTF("Adding to prefix hash:\n%.*H\n", + apduLength - hashOffset, + G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); + blake256_Update(&btchip_context_D.transactionHashPrefix, + G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, + apduLength - hashOffset); + blake256_Update(&btchip_context_D.transactionHashAuthorization, + G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, + apduLength - hashOffset); if (btchip_context_D.transactionContext.firstSigned) { if ((btchip_context_D.currentOutputOffset + apduLength) > @@ -302,23 +296,21 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_INCORRECT_DATA; goto discardTransaction; } - os_memmove(btchip_context_D.currentOutput + - btchip_context_D.currentOutputOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); + os_memmove(btchip_context_D.currentOutput + btchip_context_D.currentOutputOffset, + G_io_apdu_buffer + ISO_OFFSET_CDATA, + apduLength); btchip_context_D.currentOutputOffset += apduLength; // Check if the legacy UI can be applied if ((G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_LAST) && - !btchip_context_D.tmpCtx.output.multipleOutput && - prepare_full_output(1)) { + !btchip_context_D.tmpCtx.output.multipleOutput && prepare_full_output(1)) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_HANDLE_LEGACY; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_HANDLE_LEGACY; btchip_context_D.remainingOutputs = 0; } else { // parse outputs until one can be displayed while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) ; // Finalize the TX if necessary @@ -326,8 +318,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( if ((btchip_context_D.remainingOutputs == 0) && (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_FINALIZE_TX; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; } } } @@ -344,15 +335,12 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( blake256_Final(&btchip_context_D.transactionHashAuthorization, authorizationHash); - - if(btchip_context_D.transactionContext.firstSigned) { + if (btchip_context_D.transactionContext.firstSigned) { if (!btchip_context_D.tmpCtx.output.changeInitialized) { - os_memset(transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); + os_memset(transactionSummary, 0, sizeof(btchip_transaction_summary_t)); } - transactionSummary->payToAddressVersion = - btchip_context_D.payToAddressVersion; + transactionSummary->payToAddressVersion = btchip_context_D.payToAddressVersion; transactionSummary->payToScriptHashVersion = btchip_context_D.payToScriptHashVersion; @@ -377,36 +365,33 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( os_memmove(transactionSummary->authorizationHash, authorizationHash, sizeof(transactionSummary->authorizationHash)); - goto return_OK; + goto return_OK; } else { - if (btchip_secure_memcmp( - authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { + if (btchip_secure_memcmp(authorizationHash, + transactionSummary->authorizationHash, + sizeof(transactionSummary->authorizationHash))) { PRINTF("Authorization hash doesn't match the previous one\n"); sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; -discardTransaction: + discardTransaction: CLOSE_TRY; goto catch_discardTransaction; - } - else { + } else { PRINTF("Authorization Hash OK:\n%.*H\n", 32, authorizationHash); } } - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_SIGN_READY; sw = BTCHIP_SW_OK; } CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0x0F); catch_discardTransaction: - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; - os_memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, + os_memmove(G_io_apdu_buffer, + btchip_context_D.currentOutput, btchip_context_D.currentOutputOffset); btchip_context_D.outLength = btchip_context_D.currentOutputOffset; } @@ -420,32 +405,28 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( unsigned short btchip_apdu_hash_input_finalize_full() { PRINTF("state=%d\n", btchip_context_D.outputParsingState); - unsigned short sw = btchip_apdu_hash_input_finalize_full_internal( - &btchip_context_D.transactionSummary); + unsigned short sw = + btchip_apdu_hash_input_finalize_full_internal(&btchip_context_D.transactionSummary); if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { // if the UI reject the processing of the request, then reply // immediately bool status; - if(btchip_context_D.outputParsingState == BTCHIP_BIP44_CHANGE_PATH_VALIDATION) { + if (btchip_context_D.outputParsingState == BTCHIP_BIP44_CHANGE_PATH_VALIDATION) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; return sw; - } - else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { + } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { PRINTF("BAGL finalize tx:\n"); status = btchip_bagl_finalize_tx(); - } else if (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_HANDLE_LEGACY) { + } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_HANDLE_LEGACY) { PRINTF("BAGL confirm output legacy:\n"); status = btchip_bagl_confirm_full_output(); - } - else { + } else { PRINTF("BAGL confirm single output:\n"); status = btchip_bagl_confirm_single_output(); } if (!status) { btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; sw = BTCHIP_SW_INCORRECT_DATA; } @@ -460,28 +441,22 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { if (confirming) { // Check if all inputs have been confirmed - if (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_PARSING_OUTPUT) { + if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_PARSING_OUTPUT) { btchip_context_D.remainingOutputs--; PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); } while (btchip_context_D.remainingOutputs != 0) { os_memmove(btchip_context_D.currentOutput, - btchip_context_D.currentOutput + - btchip_context_D.discardSize, - btchip_context_D.currentOutputOffset - - btchip_context_D.discardSize); - btchip_context_D.currentOutputOffset -= - btchip_context_D.discardSize; + btchip_context_D.currentOutput + btchip_context_D.discardSize, + btchip_context_D.currentOutputOffset - btchip_context_D.discardSize); + btchip_context_D.currentOutputOffset -= btchip_context_D.discardSize; btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + while (handle_output_state() && (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) ; if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { if (!btchip_bagl_confirm_single_output()) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_INCORRECT_DATA; break; } else { @@ -494,15 +469,12 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { } } - if ((btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_PARSING_OUTPUT) && + if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_PARSING_OUTPUT) && (btchip_context_D.remainingOutputs == 0)) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; if (!btchip_bagl_finalize_tx()) { - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_PARSING_NONE; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_INCORRECT_DATA; } else { // Let the UI play @@ -510,22 +482,16 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { } } - if ((btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_FINALIZE_TX) || - (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_HANDLE_LEGACY)) { + if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) || + (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_HANDLE_LEGACY)) { btchip_context_D.transactionContext.firstSigned = 0; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; - + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_SIGN_READY; } - btchip_context_D.outLength -= - 2; // status was already set by the last call + btchip_context_D.outLength -= 2; // status was already set by the last call } else { // Discard transaction - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; btchip_context_D.outLength = 0; } diff --git a/src/btchip_apdu_hash_input_start.c b/src/btchip_apdu_hash_input_start.c index 6f02518..f2fcc82 100644 --- a/src/btchip_apdu_hash_input_start.c +++ b/src/btchip_apdu_hash_input_start.c @@ -1,44 +1,40 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -#define P1_FIRST 0x00 -#define P1_NEXT 0x80 -#define P2_NEW 0x00 +#define P1_FIRST 0x00 +#define P1_NEXT 0x80 +#define P2_NEW 0x00 #define P2_CONTINUE 0x80 - unsigned short btchip_apdu_hash_input_start() { unsigned char apduLength; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; PRINTF("\n### HASH_INPUT_START:\n"); - if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { // Initialize - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; - } - else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { + } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -62,17 +58,14 @@ unsigned short btchip_apdu_hash_input_start() { btchip_context_D.transactionContext.relaxed = 0; btchip_set_check_internal_structure_integrity(1); // Initialize for screen pairing - os_memset(&btchip_context_D.tmpCtx.output, 0, - sizeof(btchip_context_D.tmpCtx.output)); + os_memset(&btchip_context_D.tmpCtx.output, 0, sizeof(btchip_context_D.tmpCtx.output)); btchip_context_D.tmpCtx.output.changeAccepted = 1; } - } - else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { + } else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { return BTCHIP_SW_INCORRECT_P1_P2; } - btchip_context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA; + btchip_context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA; btchip_context_D.transactionDataRemaining = apduLength; transaction_parse(PARSE_MODE_SIGNATURE); diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 420dcd6..54ecb85 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -21,7 +21,6 @@ #define SIGHASH_ALL 0x01 unsigned short btchip_apdu_hash_sign() { - PRINTF("\n### HASH_SIGN:\n"); unsigned long int lockTime; @@ -37,9 +36,7 @@ unsigned short btchip_apdu_hash_sign() { unsigned char keyPath[MAX_BIP32_PATH_LENGTH]; cx_sha256_t localHash; - - if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) && - (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { + if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) && (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -53,7 +50,8 @@ unsigned short btchip_apdu_hash_sign() { btchip_set_check_internal_structure_integrity(0); if (btchip_context_D.transactionContext.transactionState != BTCHIP_TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", btchip_context_D.transactionContext.transactionState); + PRINTF("Invalid transaction state %d\n", + btchip_context_D.transactionContext.transactionState); sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } @@ -65,8 +63,7 @@ unsigned short btchip_apdu_hash_sign() { CLOSE_TRY; goto catch_discardTransaction; } - os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); + os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; lockTime = btchip_read_u32(parameters, 1, 0); @@ -76,8 +73,7 @@ unsigned short btchip_apdu_hash_sign() { sighashType = *(parameters++); PRINTF("SighashType: %d\n", sighashType); - if (((N_btchip.bkp.config.options & - BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { + if (((N_btchip.bkp.config.options & BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { // if bitcoin cash OR forkid is set, then use the fork id if (G_coin_config->forkid) { #define SIGHASH_FORKID 0x40 @@ -109,8 +105,9 @@ unsigned short btchip_apdu_hash_sign() { btchip_write_u32_le(dataBuffer + 4, expiry); PRINTF("Finalize hash with %.*H\n", sizeof(dataBuffer), dataBuffer); - - blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, sizeof(dataBuffer)); + blake256_Update(&btchip_context_D.transactionHashPrefix, + dataBuffer, + sizeof(dataBuffer)); blake256_Final(&btchip_context_D.transactionHashPrefix, hash1); PRINTF("Hash1 %.*H\n", sizeof(hash1), hash1); @@ -121,26 +118,28 @@ unsigned short btchip_apdu_hash_sign() { btchip_write_u32_le(dataBuffer, sighashType); // include sighash type PRINTF("Sighash type: %.*H\n", 4, dataBuffer); - blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, 4); + blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, 4); // include prefix_hash PRINTF("Prefix hash: %.*H\n", sizeof(hash1), hash1); - blake256_Update(&btchip_context_D.transactionHashPrefix, hash1, sizeof(hash1)); + blake256_Update(&btchip_context_D.transactionHashPrefix, hash1, sizeof(hash1)); // include witness_hash PRINTF("Witness hash: %.*H\n", sizeof(hash2), hash2); - blake256_Update(&btchip_context_D.transactionHashPrefix, hash2, sizeof(hash2)); + blake256_Update(&btchip_context_D.transactionHashPrefix, hash2, sizeof(hash2)); // final signature hash blake256_Final(&btchip_context_D.transactionHashPrefix, hash2); PRINTF("Hash to sign: %.*H\n", sizeof(hash2), hash2); - // Sign PRINTF("Pub key: %.*H\n", sizeof(public_key_D.W), public_key_D.W); btchip_signverify_finalhash( - &btchip_private_key_D, 1, hash2, sizeof(hash2), - G_io_apdu_buffer, sizeof(G_io_apdu_buffer), - ((N_btchip.bkp.config.options & - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + &btchip_private_key_D, + 1, + hash2, + sizeof(hash2), + G_io_apdu_buffer, + sizeof(G_io_apdu_buffer), + ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; G_io_apdu_buffer[btchip_context_D.outLength++] = sighashType; @@ -152,8 +151,7 @@ unsigned short btchip_apdu_hash_sign() { CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0xF); catch_discardTransaction: - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; } FINALLY { btchip_set_check_internal_structure_integrity(1); diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 79a4a10..6ac29ff 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -1,33 +1,33 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" #define P1_PREPARE 0x00 -#define P1_SIGN 0x80 -#define P2_LEGACY 0x00 -#define P2_FIRST 0x01 -#define P2_OTHER 0x80 +#define P1_SIGN 0x80 +#define P2_LEGACY 0x00 +#define P2_FIRST 0x01 +#define P2_OTHER 0x80 -#define BITID_NONE 0 +#define BITID_NONE 0 #define BITID_POWERCYCLE 1 -#define BITID_MULTIPLE 2 +#define BITID_MULTIPLE 2 //#define SLIP_13 0x8000000D @@ -86,7 +86,8 @@ unsigned short btchip_apdu_sign_message_internal() { unsigned char chunkLength; unsigned char messageLength[3]; unsigned char messageLengthSize; - os_memset(&btchip_context_D.transactionSummary, 0, + os_memset(&btchip_context_D.transactionSummary, + 0, sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { PRINTF("Invalid path\n"); @@ -98,9 +99,9 @@ unsigned short btchip_apdu_sign_message_internal() { btchip_context_D.payToAddressVersion; btchip_context_D.transactionSummary.payToScriptHashVersion = btchip_context_D.payToScriptHashVersion; - os_memmove( - btchip_context_D.transactionSummary.summarydata.keyPath, - G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); + os_memmove(btchip_context_D.transactionSummary.summarydata.keyPath, + G_io_apdu_buffer + offset, + MAX_BIP32_PATH_LENGTH); offset += (4 * G_io_apdu_buffer[offset]) + 1; if (p2 == P2_LEGACY) { btchip_context_D.transactionSummary.messageLength = @@ -108,12 +109,10 @@ unsigned short btchip_apdu_sign_message_internal() { offset++; } else { btchip_context_D.transactionSummary.messageLength = - (G_io_apdu_buffer[offset] << 8) | - (G_io_apdu_buffer[offset + 1]); + (G_io_apdu_buffer[offset] << 8) | (G_io_apdu_buffer[offset + 1]); offset += 2; } - if (btchip_context_D.transactionSummary.messageLength == - 0) { + if (btchip_context_D.transactionSummary.messageLength == 0) { PRINTF("Null message length\n"); sw = BTCHIP_SW_INCORRECT_DATA; CLOSE_TRY; @@ -121,35 +120,43 @@ unsigned short btchip_apdu_sign_message_internal() { } btchip_context_D.hashedMessageLength = 0; cx_sha256_init(&btchip_context_D.transactionHashPrefix); - cx_sha256_init( - &btchip_context_D.transactionHashWitness); - chunkLength = - btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH; - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, - &chunkLength, 1, NULL, 0); - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + cx_sha256_init(&btchip_context_D.transactionHashWitness); + chunkLength = btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH; + cx_hash(&btchip_context_D.transactionHashPrefix.header, + 0, + &chunkLength, + 1, + NULL, + 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, + 0, btchip_context_D.coinId, - btchip_context_D.coinIdLength, NULL, 0); - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, - (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0); - if (btchip_context_D.transactionSummary.messageLength < - 0xfd) { - messageLength[0] = - btchip_context_D.transactionSummary.messageLength; + btchip_context_D.coinIdLength, + NULL, + 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, + 0, + (unsigned char *) SIGNMAGIC, + SIGNMAGIC_LENGTH, + NULL, + 0); + if (btchip_context_D.transactionSummary.messageLength < 0xfd) { + messageLength[0] = btchip_context_D.transactionSummary.messageLength; messageLengthSize = 1; } else { messageLength[0] = 0xfd; messageLength[1] = - (btchip_context_D.transactionSummary.messageLength & - 0xff); - messageLength[2] = ((btchip_context_D.transactionSummary - .messageLength >> - 8) & - 0xff); + (btchip_context_D.transactionSummary.messageLength & 0xff); + messageLength[2] = + ((btchip_context_D.transactionSummary.messageLength >> 8) & 0xff); messageLengthSize = 3; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, - messageLength, messageLengthSize, NULL, 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, + 0, + messageLength, + messageLengthSize, + NULL, + 0); chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); if ((btchip_context_D.hashedMessageLength + chunkLength) > btchip_context_D.transactionSummary.messageLength) { @@ -158,11 +165,18 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, - G_io_apdu_buffer + offset, chunkLength, NULL, 0); - cx_hash( - &btchip_context_D.transactionHashWitness.header, - 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, + 0, + G_io_apdu_buffer + offset, + chunkLength, + NULL, + 0); + cx_hash(&btchip_context_D.transactionHashWitness.header, + 0, + G_io_apdu_buffer + offset, + chunkLength, + NULL, + 0); btchip_context_D.hashedMessageLength += chunkLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -180,11 +194,18 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, - G_io_apdu_buffer + offset, apduLength, NULL, 0); - cx_hash( - &btchip_context_D.transactionHashWitness.header, - 0, G_io_apdu_buffer + offset, apduLength, NULL, 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, + 0, + G_io_apdu_buffer + offset, + apduLength, + NULL, + 0); + cx_hash(&btchip_context_D.transactionHashWitness.header, + 0, + G_io_apdu_buffer + offset, + apduLength, + NULL, + 0); btchip_context_D.hashedMessageLength += apduLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -204,8 +225,8 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - if (checkBitId(btchip_context_D.transactionSummary.summarydata - .keyPath) != BITID_NONE) { + if (checkBitId(btchip_context_D.transactionSummary.summarydata.keyPath) != + BITID_NONE) { sw = btchip_compute_hash(); } else { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; @@ -218,8 +239,7 @@ unsigned short btchip_apdu_sign_message_internal() { sw = SW_TECHNICAL_DETAILS(0x0F); } discard : { - os_memset(&btchip_context_D.transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); + os_memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); } FINALLY { return sw; @@ -242,26 +262,28 @@ unsigned short btchip_compute_hash() { btchip_context_D.outLength = 0; BEGIN_TRY { TRY { - cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, - 0, hash, 32); + cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, 0, hash, 32); cx_sha256_init(&btchip_context_D.transactionHashPrefix); - cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, - 32, hash, 32); - btchip_private_derive_keypair( - btchip_context_D.transactionSummary.summarydata.keyPath, 0, - NULL); + cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, 32, hash, 32); + btchip_private_derive_keypair(btchip_context_D.transactionSummary.summarydata.keyPath, + 0, + NULL); btchip_signverify_finalhash( - &btchip_private_key_D, 1, hash, sizeof(hash), // IN - G_io_apdu_buffer, 100, // OUT - ((N_btchip.bkp.config.options & - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + &btchip_private_key_D, + 1, + hash, + sizeof(hash), // IN + G_io_apdu_buffer, + 100, // OUT + ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; } CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0x0F); } FINALLY { - os_memset(&btchip_context_D.transactionSummary, 0, + os_memset(&btchip_context_D.transactionSummary, + 0, sizeof(btchip_transaction_summary_t)); } } diff --git a/src/btchip_bagl_extensions.h b/src/btchip_bagl_extensions.h index b50aa58..11e53d0 100644 --- a/src/btchip_bagl_extensions.h +++ b/src/btchip_bagl_extensions.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #ifndef _BTCHIP_BAGL_H_ #define _BTCHIP_BAGL_H_ @@ -43,7 +43,7 @@ void btchip_bagl_confirm_message_signature(void); void btchip_bagl_user_action_message_signing(unsigned char confirming); // Public key display -void btchip_bagl_display_public_key(unsigned char *derivation_path); +void btchip_bagl_display_public_key(unsigned char* derivation_path); void btchip_bagl_user_action_display(unsigned char confirming); void btchip_bagl_request_pubkey_approval(void); diff --git a/src/btchip_base58.c b/src/btchip_base58.c index 5bb2f8b..5577888 100644 --- a/src/btchip_base58.c +++ b/src/btchip_base58.c @@ -1,134 +1,135 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #define MAX_DEC_INPUT_SIZE 164 #define MAX_ENC_INPUT_SIZE 120 -int btchip_decode_base58(const char *in, size_t length, - unsigned char *out, size_t *outlen) { - unsigned char tmp[MAX_DEC_INPUT_SIZE]; - unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; - unsigned char i; - unsigned char j; - unsigned char startAt; - unsigned char zeroCount = 0; - if (length > MAX_DEC_INPUT_SIZE) { - return -1; - } - os_memmove(tmp, in, length); - PRINTF("To decode\n%.*H\n",length,tmp); - for (i = 0; i < length; i++) { - if (in[i] >= sizeof(BASE58TABLE)) { - return -1; +int btchip_decode_base58(const char *in, size_t length, unsigned char *out, size_t *outlen) { + unsigned char tmp[MAX_DEC_INPUT_SIZE]; + unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; + unsigned char i; + unsigned char j; + unsigned char startAt; + unsigned char zeroCount = 0; + if (length > MAX_DEC_INPUT_SIZE) { + return -1; } - tmp[i] = BASE58TABLE[(int)in[i]]; - if (tmp[i] == 0xff) { - return -1; + os_memmove(tmp, in, length); + PRINTF("To decode\n%.*H\n", length, tmp); + for (i = 0; i < length; i++) { + if (in[i] >= sizeof(BASE58TABLE)) { + return -1; + } + tmp[i] = BASE58TABLE[(int) in[i]]; + if (tmp[i] == 0xff) { + return -1; + } } - } - while ((zeroCount < length) && (tmp[zeroCount] == 0)) { - ++zeroCount; - } - j = length; - startAt = zeroCount; - while (startAt < length) { - unsigned short remainder = 0; - unsigned char divLoop; - for (divLoop = startAt; divLoop < length; divLoop++) { - unsigned short digit256 = (unsigned short)(tmp[divLoop] & 0xff); - unsigned short tmpDiv = remainder * 58 + digit256; - tmp[divLoop] = (unsigned char)(tmpDiv / 256); - remainder = (tmpDiv % 256); + while ((zeroCount < length) && (tmp[zeroCount] == 0)) { + ++zeroCount; } - if (tmp[startAt] == 0) { - ++startAt; + j = length; + startAt = zeroCount; + while (startAt < length) { + unsigned short remainder = 0; + unsigned char divLoop; + for (divLoop = startAt; divLoop < length; divLoop++) { + unsigned short digit256 = (unsigned short) (tmp[divLoop] & 0xff); + unsigned short tmpDiv = remainder * 58 + digit256; + tmp[divLoop] = (unsigned char) (tmpDiv / 256); + remainder = (tmpDiv % 256); + } + if (tmp[startAt] == 0) { + ++startAt; + } + buffer[--j] = (unsigned char) remainder; + } + while ((j < length) && (buffer[j] == 0)) { + ++j; + } + length = length - (j - zeroCount); + if (*outlen < length) { + PRINTF("Decode overflow %d %d\n", length, *outlen); + return -1; } - buffer[--j] = (unsigned char)remainder; - } - while ((j < length) && (buffer[j] == 0)) { - ++j; - } - length = length - (j - zeroCount); - if (*outlen < length) { - PRINTF("Decode overflow %d %d\n", length, *outlen); - return -1; - } - os_memmove(out, buffer + j - zeroCount, length); - PRINTF("Decoded\n%.*H\n",length,out); - *outlen = length; - return 0; + os_memmove(out, buffer + j - zeroCount, length); + PRINTF("Decoded\n%.*H\n", length, out); + *outlen = length; + return 0; } -int btchip_encode_base58(const unsigned char *in, size_t length, - unsigned char *out, size_t *outlen) { - unsigned char buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; - size_t i = 0, j; - size_t startAt, stopAt; - size_t zeroCount = 0; - size_t outputSize; +int btchip_encode_base58(const unsigned char *in, + size_t length, + unsigned char *out, + size_t *outlen) { + unsigned char buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; + size_t i = 0, j; + size_t startAt, stopAt; + size_t zeroCount = 0; + size_t outputSize; - if (length > MAX_ENC_INPUT_SIZE) { - return -1; - } + if (length > MAX_ENC_INPUT_SIZE) { + return -1; + } - PRINTF("Length to encode %d\n", length); - PRINTF("To encode\n%.*H\n",length,in); + PRINTF("Length to encode %d\n", length); + PRINTF("To encode\n%.*H\n", length, in); - while ((zeroCount < length) && (in[zeroCount] == 0)) { - ++zeroCount; - } + while ((zeroCount < length) && (in[zeroCount] == 0)) { + ++zeroCount; + } - outputSize = (length - zeroCount) * 138 / 100 + 1; - stopAt = outputSize - 1; - for (startAt = zeroCount; startAt < length; startAt++) { - int carry = in[startAt]; - for (j = outputSize - 1; (int)j >= 0; j--) { - carry += 256 * buffer[j]; - buffer[j] = carry % 58; - carry /= 58; + outputSize = (length - zeroCount) * 138 / 100 + 1; + stopAt = outputSize - 1; + for (startAt = zeroCount; startAt < length; startAt++) { + int carry = in[startAt]; + for (j = outputSize - 1; (int) j >= 0; j--) { + carry += 256 * buffer[j]; + buffer[j] = carry % 58; + carry /= 58; - if (j <= stopAt - 1 && carry == 0) { - break; - } + if (j <= stopAt - 1 && carry == 0) { + break; + } + } + stopAt = j; } - stopAt = j; - } - j = 0; - while (j < outputSize && buffer[j] == 0) { - j += 1; - } + j = 0; + while (j < outputSize && buffer[j] == 0) { + j += 1; + } - if (*outlen < zeroCount + outputSize - j) { - *outlen = zeroCount + outputSize - j; - return -1; - } + if (*outlen < zeroCount + outputSize - j) { + *outlen = zeroCount + outputSize - j; + return -1; + } - os_memset(out, BASE58ALPHABET[0], zeroCount); + os_memset(out, BASE58ALPHABET[0], zeroCount); - i = zeroCount; - while (j < outputSize) { - out[i++] = BASE58ALPHABET[buffer[j++]]; - } - *outlen = i; - PRINTF("Length encoded %d\n", i); - PRINTF("Encoded\n%.*H\n",i,out); - return 0; + i = zeroCount; + while (j < outputSize) { + out[i++] = BASE58ALPHABET[buffer[j++]]; + } + *outlen = i; + PRINTF("Length encoded %d\n", i); + PRINTF("Encoded\n%.*H\n", i, out); + return 0; } diff --git a/src/btchip_bcd.c b/src/btchip_bcd.c index 9f15f44..4d0ff70 100644 --- a/src/btchip_bcd.c +++ b/src/btchip_bcd.c @@ -1,26 +1,25 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #define SCRATCH_SIZE 21 -unsigned char -btchip_convert_hex_amount_to_displayable(unsigned char *amount) { +unsigned char btchip_convert_hex_amount_to_displayable(unsigned char *amount) { unsigned char LOOP1; unsigned char LOOP2; @@ -45,8 +44,7 @@ btchip_convert_hex_amount_to_displayable(unsigned char *amount) { for (j = 0; j < 8; j++) { unsigned char k; unsigned short shifted_in = - (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1 - : (short)0; + (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short) 1 : (short) 0; for (k = smin; k < nscratch; k++) { scratch[k] += ((scratch[k] >= 5) ? 3 : 0); } @@ -54,11 +52,10 @@ btchip_convert_hex_amount_to_displayable(unsigned char *amount) { smin -= 1; } for (k = smin; k < nscratch - 1; k++) { - scratch[k] = - ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); + scratch[k] = ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); } - scratch[nscratch - 1] = ((scratch[nscratch - 1] << 1) & 0x0F) | - (shifted_in == 1 ? 1 : 0); + scratch[nscratch - 1] = + ((scratch[nscratch - 1] << 1) & 0x0F) | (shifted_in == 1 ? 1 : 0); } } diff --git a/src/btchip_context.c b/src/btchip_context.c index 4e20847..687c198 100644 --- a/src/btchip_context.c +++ b/src/btchip_context.c @@ -1,36 +1,36 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" -void autosetup(void){ +void autosetup(void) { btchip_config_t config; unsigned char i; unsigned char tmp[32]; os_memset(&config, 0, sizeof(btchip_config_t)); config.options |= BTCHIP_OPTION_DETERMINISTIC_SIGNATURE; - config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when - // supporting multi output + config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when + // supporting multi output - nvm_write((void *)&N_btchip.bkp.config, &config, sizeof(config)); + nvm_write((void *) &N_btchip.bkp.config, &config, sizeof(config)); cx_rng(tmp, sizeof(tmp)); - nvm_write((void *)&N_btchip.bkp.trustedinput_key, tmp, sizeof(tmp)); + nvm_write((void *) &N_btchip.bkp.trustedinput_key, tmp, sizeof(tmp)); i = 1; - nvm_write((void *)&N_btchip.config_valid, &i, 1); + nvm_write((void *) &N_btchip.config_valid, &i, 1); } /** @@ -43,11 +43,9 @@ void btchip_context_init() { SB_SET(btchip_context_D.halted, 0); btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - os_memset(btchip_context_D.totalOutputAmount, 0, - sizeof(btchip_context_D.totalOutputAmount)); + os_memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; - if (N_btchip.config_valid != 0x01) { autosetup(); } @@ -57,24 +55,23 @@ void btchip_context_init() { PRINTF("No configuration found\n"); defaultMode = BTCHIP_MODE_WALLET; - } - else { + } else { btchip_context_D.payToAddressVersion = G_coin_config->p2pkh_version; btchip_context_D.payToScriptHashVersion = G_coin_config->p2sh_version; btchip_context_D.coinFamily = G_coin_config->family; btchip_context_D.coinIdLength = strlen(PIC(G_coin_config->coinid)); - os_memmove(btchip_context_D.coinId, PIC(G_coin_config->coinid), + os_memmove(btchip_context_D.coinId, + PIC(G_coin_config->coinid), btchip_context_D.coinIdLength); - btchip_context_D.shortCoinIdLength = - strlen(PIC(G_coin_config->name_short)); - os_memmove(btchip_context_D.shortCoinId, PIC(G_coin_config->name_short), + btchip_context_D.shortCoinIdLength = strlen(PIC(G_coin_config->name_short)); + os_memmove(btchip_context_D.shortCoinId, + PIC(G_coin_config->name_short), btchip_context_D.shortCoinIdLength); - } if (!N_btchip.storageInitialized) { - unsigned char initialized = 1, denied=1; + unsigned char initialized = 1, denied = 1; - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &denied, 1); - nvm_write((void *)&N_btchip.storageInitialized, &initialized, 1); + nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &denied, 1); + nvm_write((void *) &N_btchip.storageInitialized, &initialized, 1); } } \ No newline at end of file diff --git a/src/btchip_ecc.c b/src/btchip_ecc.c index 514fc0a..f7ff79c 100644 --- a/src/btchip_ecc.c +++ b/src/btchip_ecc.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index a1de9a1..28a63df 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -1,40 +1,43 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "blake256.h" const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { - 0x19, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG + 0x19, + 0x76, + 0xA9, + 0x14}; // script length, OP_DUP, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = {0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL + 0x17, + 0xA9, + 0x14}; // script length, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; unsigned char btchip_output_script_is_regular(unsigned char *buffer) { - if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && + if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == + 0) && (os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, TRANSACTION_OUTPUT_SCRIPT_POST, sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { @@ -45,7 +48,8 @@ unsigned char btchip_output_script_is_regular(unsigned char *buffer) { } unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { - if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + if ((os_memcmp(buffer, + TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && (os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, @@ -60,15 +64,13 @@ unsigned char btchip_output_script_is_op_return(unsigned char *buffer) { } unsigned char btchip_output_script_is_op_create(unsigned char *buffer) { - return (!btchip_output_script_is_regular(buffer) && - !btchip_output_script_is_p2sh(buffer) && + return (!btchip_output_script_is_regular(buffer) && !btchip_output_script_is_p2sh(buffer) && !btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && (buffer[buffer[0]] == 0xC1)); } unsigned char btchip_output_script_is_op_call(unsigned char *buffer) { - return (!btchip_output_script_is_regular(buffer) && - !btchip_output_script_is_p2sh(buffer) && + return (!btchip_output_script_is_regular(buffer) && !btchip_output_script_is_p2sh(buffer) && !btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && (buffer[buffer[0]] == 0xC2)); } @@ -82,12 +84,10 @@ unsigned char btchip_rng_u8_modulo(unsigned char modulo) { return (candidate % modulo); } -unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, - unsigned short length) { +unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, unsigned short length) { unsigned char error = 0; while (length--) { - error |= ((unsigned char *)buf1)[length] ^ - ((unsigned char *)buf2)[length]; + error |= ((unsigned char *) buf1)[length] ^ ((unsigned char *) buf2)[length]; } if (length != 0xffff) { return 1; @@ -95,17 +95,16 @@ unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, return error; } -unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, - unsigned char skipSign) { +unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, unsigned char skipSign) { unsigned char i; unsigned long int result = 0; unsigned char shiftValue = (be ? 24 : 0); for (i = 0; i < 4; i++) { - unsigned char x = (unsigned char)buffer[i]; + unsigned char x = (unsigned char) buffer[i]; if ((i == 0) && skipSign) { x &= 0x7f; } - result += ((unsigned long int)x) << shiftValue; + result += ((unsigned long int) x) << shiftValue; if (be) { shiftValue -= 8; } else { @@ -129,18 +128,15 @@ void btchip_write_u32_le(unsigned char *buffer, unsigned long int value) { buffer[3] = ((value >> 24) & 0xff); } -void btchip_retrieve_keypair_discard(unsigned char *privateComponent, - unsigned char derivePublic) { +void btchip_retrieve_keypair_discard(unsigned char *privateComponent, unsigned char derivePublic) { BEGIN_TRY { TRY { - cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, - &btchip_private_key_D); + cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, &btchip_private_key_D); - PRINTF("Using private component\n%.*H\n",32,privateComponent); + PRINTF("Using private component\n%.*H\n", 32, privateComponent); if (derivePublic) { - cx_ecfp_generate_pair(BTCHIP_CURVE, &btchip_public_key_D, - &btchip_private_key_D, 1); + cx_ecfp_generate_pair(BTCHIP_CURVE, &btchip_public_key_D, &btchip_private_key_D, 1); } } FINALLY { @@ -149,8 +145,7 @@ void btchip_retrieve_keypair_discard(unsigned char *privateComponent, END_TRY; } -void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char *out) { +void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out) { union { BLAKE256_CTX blake; cx_ripemd160_t riprip; @@ -164,21 +159,23 @@ void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, cx_hash(&u.riprip.header, CX_LAST, buffer, 32, out, 32); } -unsigned short btchip_public_key_to_encoded_base58( - unsigned char *in, unsigned short inlen, unsigned char *out, - unsigned short outlen, unsigned short version, - unsigned char alreadyHashed) { +unsigned short btchip_public_key_to_encoded_base58(unsigned char *in, + unsigned short inlen, + unsigned char *out, + unsigned short outlen, + unsigned short version, + unsigned char alreadyHashed) { unsigned char tmpBuffer[26]; unsigned char checksumBuffer[32]; - //cx_blake2b_t hash; + // cx_blake2b_t hash; BLAKE256_CTX hash; unsigned char versionSize = (version > 255 ? 2 : 1); size_t outputLen; if (!alreadyHashed) { - PRINTF("To hash\n%.*H\n",inlen,in); + PRINTF("To hash\n%.*H\n", inlen, in); btchip_public_key_hash160(in, inlen, tmpBuffer + versionSize); - PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); + PRINTF("Hash160\n%.*H\n", 20, (tmpBuffer + versionSize)); if (version > 255) { tmpBuffer[0] = (version >> 8); tmpBuffer[1] = version; @@ -196,7 +193,7 @@ unsigned short btchip_public_key_to_encoded_base58( blake256_Update(&hash, checksumBuffer, 32); blake256_Final(&hash, checksumBuffer); - PRINTF("Checksum\n%.*H\n",4,checksumBuffer); + PRINTF("Checksum\n%.*H\n", 4, checksumBuffer); os_memmove(tmpBuffer + 20 + versionSize, checksumBuffer, 4); outputLen = outlen; @@ -206,8 +203,7 @@ unsigned short btchip_public_key_to_encoded_base58( return outputLen; } -void btchip_swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size) { +void btchip_swap_bytes(unsigned char *target, unsigned char *source, unsigned char size) { unsigned char i; for (i = 0; i < size; i++) { target[i] = source[size - 1 - i]; @@ -221,7 +217,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, unsigned char hashBuffer[32]; cx_sha256_t hash; size_t outputLen = outlen; - if (btchip_decode_base58((char *)in, inlen, out, &outputLen) < 0) { + if (btchip_decode_base58((char *) in, inlen, out, &outputLen) < 0) { THROW(EXCEPTION); } outlen = outputLen; @@ -233,7 +229,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, cx_hash(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer, 32); if (os_memcmp(out + outlen - 4, hashBuffer, 4)) { - PRINTF("Hash checksum mismatch\n%.*H\n",sizeof(hashBuffer),hashBuffer); + PRINTF("Hash checksum mismatch\n%.*H\n", sizeof(hashBuffer), hashBuffer); THROW(INVALID_CHECKSUM); } @@ -257,8 +253,11 @@ void btchip_private_derive_keypair(unsigned char *bip32Path, bip32PathInt[i] = btchip_read_u32(bip32Path, 1, 0); bip32Path += 4; } - os_perso_derive_node_bip32(CX_CURVE_256K1, bip32PathInt, bip32PathLength, - privateComponent, out_chainCode); + os_perso_derive_node_bip32(CX_CURVE_256K1, + bip32PathInt, + bip32PathLength, + privateComponent, + out_chainCode); btchip_retrieve_keypair_discard(privateComponent, derivePublic); os_memset(privateComponent, 0, sizeof(privateComponent)); } @@ -268,7 +267,6 @@ Checks if the values of a derivation path are within "normal" (arbitrary) ranges Account < 100, change == 1 or 0, address index < 50000 Returns 1 if the path is unusual, or not compliant with BIP44*/ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path) { - unsigned char i, path_len; unsigned int bip32PathInt[MAX_BIP32_PATH]; @@ -283,18 +281,19 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa bip32Path += 4; } - // If the path length is not compliant with BIP44 or if the purpose/coin type don't match regular usage - if(path_len != BIP44_PATH_LEN || - ((bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { + // If the path length is not compliant with BIP44 or if the purpose/coin type don't match + // regular usage + if (path_len != BIP44_PATH_LEN || ((bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 44 && + (bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 49 && + (bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 84)) { return 1; } // If the account or address index is very high or if the change isn't 1, return a warning - if((bip32PathInt[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || - bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + if ((bip32PathInt[BIP44_ACCOUNT_OFFSET] ^ 0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || + bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path + ? 1 + : 0 || bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { return 1; } @@ -302,9 +301,9 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa } // Print a BIP32 path as an ascii string to display on the device screen -// On the Ledger Blue, if the string is longer than 30 char, the string will be split in multiple lines -unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len) { - +// On the Ledger Blue, if the string is longer than 30 char, the string will be split in multiple +// lines +unsigned char bip32_print_path(unsigned char *bip32Path, char *out, unsigned char max_out_len) { unsigned char bip32PathLength; unsigned char i, offset; unsigned int current_level; @@ -316,77 +315,90 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned cha } bip32Path++; out[0] = ' '; - offset=1; + offset = 1; for (i = 0; i < bip32PathLength; i++) { current_level = btchip_read_u32(bip32Path, 1, 0); - hardened = (bool)(current_level & 0x80000000); - if(hardened) { - //remove hardening flag + hardened = (bool) (current_level & 0x80000000); + if (hardened) { + // remove hardening flag current_level ^= 0x80000000; } bip32Path += 4; - snprintf(out+offset, max_out_len-offset, "%u", current_level); + snprintf(out + offset, max_out_len - offset, "%u", current_level); offset = strnlen(out, max_out_len); - if(offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); - if(hardened) out[offset++] = '\''; + if (offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); + if (hardened) out[offset++] = '\''; out[offset++] = '/'; out[offset] = '\0'; } // remove last '/' - out[offset-1] = '\0'; + out[offset - 1] = '\0'; #if defined(TARGET_BLUE) // if the path is longer than 30 char, split the string in multiple strings of length 30 - uint8_t len=strnlen(out, MAX_DERIV_PATH_ASCII_LENGTH); - uint8_t num_split = len/30; + uint8_t len = strnlen(out, MAX_DERIV_PATH_ASCII_LENGTH); + uint8_t num_split = len / 30; - for(i = 1; i<= num_split; i++) { - os_memmove(out+30*i, out+(30*i-1), len-29*i); - out[30*i-1] = '\0'; + for (i = 1; i <= num_split; i++) { + os_memmove(out + 30 * i, out + (30 * i - 1), len - 29 * i); + out[30 * i - 1] = '\0'; } #endif - return offset -1; + return offset - 1; } void btchip_transaction_add_output(unsigned char *hash160Address, - unsigned char *amount, unsigned char p2sh) { - const unsigned char *pre = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE - : TRANSACTION_OUTPUT_SCRIPT_PRE); - const unsigned char *post = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST - : TRANSACTION_OUTPUT_SCRIPT_POST); - unsigned char sizePre = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) - : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); + unsigned char *amount, + unsigned char p2sh) { + const unsigned char *pre = + (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE : TRANSACTION_OUTPUT_SCRIPT_PRE); + const unsigned char *post = + (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST : TRANSACTION_OUTPUT_SCRIPT_POST); + unsigned char sizePre = + (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); unsigned char sizePost = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST) : sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)); if (amount != NULL) { btchip_swap_bytes(btchip_context_D.tmp, amount, 8); btchip_context_D.tmp += 8; } - os_memmove(btchip_context_D.tmp, (void *)pre, sizePre); + os_memmove(btchip_context_D.tmp, (void *) pre, sizePre); btchip_context_D.tmp += sizePre; os_memmove(btchip_context_D.tmp, hash160Address, 20); btchip_context_D.tmp += 20; - os_memmove(btchip_context_D.tmp, (void *)post, sizePost); + os_memmove(btchip_context_D.tmp, (void *) post, sizePost); btchip_context_D.tmp += sizePost; } - -void btchip_signverify_finalhash(void *keyContext, unsigned char sign, - unsigned char *in, unsigned short inlen, - unsigned char *out, unsigned short outlen, +void btchip_signverify_finalhash(void *keyContext, + unsigned char sign, + unsigned char *in, + unsigned short inlen, + unsigned char *out, + unsigned short outlen, unsigned char rfc6979) { if (sign) { unsigned int info = 0; - cx_ecdsa_sign((cx_ecfp_private_key_t *)keyContext, + cx_ecdsa_sign((cx_ecfp_private_key_t *) keyContext, CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), - CX_SHA256, in, inlen, out, outlen, &info); + CX_SHA256, + in, + inlen, + out, + outlen, + &info); if (info & CX_ECCINFO_PARITY_ODD) { out[0] |= 0x01; } } else { - cx_ecdsa_verify((cx_ecfp_public_key_t *)keyContext, CX_LAST, - CX_SHA256, in, inlen, out, outlen); + cx_ecdsa_verify((cx_ecfp_public_key_t *) keyContext, + CX_LAST, + CX_SHA256, + in, + inlen, + out, + outlen); } } diff --git a/src/btchip_internal.h b/src/btchip_internal.h index c56710c..1c56313 100644 --- a/src/btchip_internal.h +++ b/src/btchip_internal.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #ifndef BTCHIP_INTERNAL_H #define BTCHIP_INTERNAL_H diff --git a/src/btchip_nvram.c b/src/btchip_nvram.c index 2f3990b..d5d7bae 100644 --- a/src/btchip_nvram.c +++ b/src/btchip_nvram.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" diff --git a/src/btchip_public_ram_key_variables.c b/src/btchip_public_ram_key_variables.c index d0ccc75..97f24b7 100644 --- a/src/btchip_public_ram_key_variables.c +++ b/src/btchip_public_ram_key_variables.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_public_ram_key_variables.h" diff --git a/src/btchip_public_ram_key_variables.h b/src/btchip_public_ram_key_variables.h index c8c9aa2..e95fa28 100644 --- a/src/btchip_public_ram_key_variables.h +++ b/src/btchip_public_ram_key_variables.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #ifndef _BTCHIP_PUBLIC_RAM_KEY_VARIABLES_H_ #define _BTCHIP_PUBLIC_RAM_KEY_VARIABLES_H_ diff --git a/src/btchip_public_ram_variables.c b/src/btchip_public_ram_variables.c index 048d9c8..90fa7af 100644 --- a/src/btchip_public_ram_variables.c +++ b/src/btchip_public_ram_variables.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_public_ram_variables.h" diff --git a/src/btchip_public_ram_variables.h b/src/btchip_public_ram_variables.h index 52522ee..978f70f 100644 --- a/src/btchip_public_ram_variables.h +++ b/src/btchip_public_ram_variables.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #ifndef _BTCHIP_PUBLIC_RAM_VARIABLES_H_ #define _BTCHIP_PUBLIC_RAM_VARIABLES_H_ diff --git a/src/btchip_rom_variables.c b/src/btchip_rom_variables.c index e5d529d..f158205 100644 --- a/src/btchip_rom_variables.c +++ b/src/btchip_rom_variables.c @@ -1,82 +1,78 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -unsigned char const HEXDIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; +unsigned char const HEXDIGITS[] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; unsigned char const BASE58TABLE[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0x10, 0xff, 0x11, 0x12, 0x13, 0x14, 0x15, 0xff, 0x16, 0x17, 0x18, 0x19, - 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0xff, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff}; + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0xff, 0x11, 0x12, 0x13, 0x14, 0x15, 0xff, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0xff, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff}; -unsigned char const BASE58ALPHABET[] = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; +unsigned char const BASE58ALPHABET[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', + 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; -unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', - 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; +unsigned char const SIGNMAGIC[] = + {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; -unsigned char const TWOPOWER[] = {0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80}; +unsigned char const TWOPOWER[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; unsigned char const DISPATCHER_CLA[] = { - BTCHIP_CLA, // btchip_apdu_get_wallet_public_key, - BTCHIP_CLA, // btchip_apdu_get_trusted_input, - BTCHIP_CLA, // btchip_apdu_hash_input_start, - BTCHIP_CLA, // btchip_apdu_hash_sign, - BTCHIP_CLA, // btchip_apdu_hash_input_finalize_full, - BTCHIP_CLA, // btchip_apdu_sign_message, - BTCHIP_CLA, // btchip_apdu_get_firmware_version, - BTCHIP_CLA, // btchip_apdu_get_coin_version + BTCHIP_CLA, // btchip_apdu_get_wallet_public_key, + BTCHIP_CLA, // btchip_apdu_get_trusted_input, + BTCHIP_CLA, // btchip_apdu_hash_input_start, + BTCHIP_CLA, // btchip_apdu_hash_sign, + BTCHIP_CLA, // btchip_apdu_hash_input_finalize_full, + BTCHIP_CLA, // btchip_apdu_sign_message, + BTCHIP_CLA, // btchip_apdu_get_firmware_version, + BTCHIP_CLA, // btchip_apdu_get_coin_version }; unsigned char const DISPATCHER_INS[] = { - BTCHIP_INS_GET_WALLET_PUBLIC_KEY, // btchip_apdu_get_wallet_public_key, - BTCHIP_INS_GET_TRUSTED_INPUT, // btchip_apdu_get_trusted_input, - BTCHIP_INS_HASH_INPUT_START, // btchip_apdu_hash_input_start, - BTCHIP_INS_HASH_SIGN, // btchip_apdu_hash_sign, - BTCHIP_INS_HASH_INPUT_FINALIZE_FULL, // btchip_apdu_hash_input_finalize_full, - BTCHIP_INS_SIGN_MESSAGE, // btchip_apdu_sign_message, - BTCHIP_INS_GET_FIRMWARE_VERSION, // btchip_apdu_get_firmware_version, - BTCHIP_INS_GET_COIN_VER, // btchip_apdu_get_coin_version + BTCHIP_INS_GET_WALLET_PUBLIC_KEY, // btchip_apdu_get_wallet_public_key, + BTCHIP_INS_GET_TRUSTED_INPUT, // btchip_apdu_get_trusted_input, + BTCHIP_INS_HASH_INPUT_START, // btchip_apdu_hash_input_start, + BTCHIP_INS_HASH_SIGN, // btchip_apdu_hash_sign, + BTCHIP_INS_HASH_INPUT_FINALIZE_FULL, // btchip_apdu_hash_input_finalize_full, + BTCHIP_INS_SIGN_MESSAGE, // btchip_apdu_sign_message, + BTCHIP_INS_GET_FIRMWARE_VERSION, // btchip_apdu_get_firmware_version, + BTCHIP_INS_GET_COIN_VER, // btchip_apdu_get_coin_version }; unsigned char const DISPATCHER_DATA_IN[] = { - 1, // btchip_apdu_get_wallet_public_key, - 1, // btchip_apdu_get_trusted_input, - 1, // btchip_apdu_hash_input_start, - 1, // btchip_apdu_hash_sign, - 1, // btchip_apdu_hash_input_finalize_full, - 1, // btchip_apdu_sign_message, - 0, // btchip_apdu_get_firmware_version, - 0, // btchip_apdu_get_coin_version + 1, // btchip_apdu_get_wallet_public_key, + 1, // btchip_apdu_get_trusted_input, + 1, // btchip_apdu_hash_input_start, + 1, // btchip_apdu_hash_sign, + 1, // btchip_apdu_hash_input_finalize_full, + 1, // btchip_apdu_sign_message, + 0, // btchip_apdu_get_firmware_version, + 0, // btchip_apdu_get_coin_version }; apduProcessingFunction const DISPATCHER_FUNCTIONS[] = { diff --git a/src/btchip_rom_variables.h b/src/btchip_rom_variables.h index 8079d65..cfc697a 100644 --- a/src/btchip_rom_variables.h +++ b/src/btchip_rom_variables.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #ifndef _BTCHIP_ROM_VARIABLES_ #define _BTCHIP_ROM_VARIABLES_ diff --git a/src/btchip_secure_value.c b/src/btchip_secure_value.c index 4fd1622..e375696 100644 --- a/src/btchip_secure_value.c +++ b/src/btchip_secure_value.c @@ -1,38 +1,38 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" void sbSet(secu8 *target, unsigned char source) { - *target = (((unsigned char)~source) << 8) + source; + *target = (((unsigned char) ~source) << 8) + source; } void sbCheck(secu8 source) { - if (((source >> 8) & 0xff) != (unsigned char)(~(source & 0xff))) { + if (((source >> 8) & 0xff) != (unsigned char) (~(source & 0xff))) { reset(); } } void ssSet(secu16 *target, unsigned short source) { - *target = (((unsigned long int)((unsigned short)~source)) << 16) + source; + *target = (((unsigned long int) ((unsigned short) ~source)) << 16) + source; } void ssCheck(secu16 source) { - if (((source >> 16) & 0xffff) != (unsigned short)(~(source & 0xffff))) { + if (((source >> 16) & 0xffff) != (unsigned short) (~(source & 0xffff))) { reset(); } } diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 22f90b6..84cceee 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -25,18 +25,18 @@ void check_transaction_available(unsigned char x) { if (btchip_context_D.transactionDataRemaining < x) { - PRINTF("Check transaction available failed %d < %d\n", btchip_context_D.transactionDataRemaining, x); + PRINTF("Check transaction available failed %d < %d\n", + btchip_context_D.transactionDataRemaining, + x); THROW(EXCEPTION); } } -#define OP_HASH160 0xA9 -#define OP_EQUAL 0x87 +#define OP_HASH160 0xA9 +#define OP_EQUAL 0x87 #define OP_CHECKMULTISIG 0xAE -unsigned char transaction_amount_add_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { +unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, unsigned char *b) { unsigned char carry = 0; unsigned char i; for (i = 0; i < 8; i++) { @@ -47,9 +47,7 @@ unsigned char transaction_amount_add_be(unsigned char *target, return carry; } -unsigned char transaction_amount_sub_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { +unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b) { unsigned char borrow = 0; unsigned char i; for (i = 0; i < 8; i++) { @@ -67,7 +65,7 @@ unsigned char transaction_amount_sub_be(unsigned char *target, borrow = 1; tmpA += 255 + 1; } - target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); + target[8 - 1 - i] = (unsigned char) (tmpA - tmpB); } return borrow; @@ -75,13 +73,19 @@ unsigned char transaction_amount_sub_be(unsigned char *target, void transaction_offset(unsigned char value) { if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { - PRINTF("Add to prefix hash: ", value ,btchip_context_D.transactionBufferPointer); - blake256_Update(&btchip_context_D.transactionHashPrefix, btchip_context_D.transactionBufferPointer, value); - blake256_Update(&btchip_context_D.transactionHashAuthorization, btchip_context_D.transactionBufferPointer, value); + PRINTF("Add to prefix hash: ", value, btchip_context_D.transactionBufferPointer); + blake256_Update(&btchip_context_D.transactionHashPrefix, + btchip_context_D.transactionBufferPointer, + value); + blake256_Update(&btchip_context_D.transactionHashAuthorization, + btchip_context_D.transactionBufferPointer, + value); } if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_WITNESS) != 0) { PRINTF("Add to witness hash: ", value, btchip_context_D.transactionBufferPointer); - blake256_Update(&btchip_context_D.transactionHashWitness, btchip_context_D.transactionBufferPointer, value); + blake256_Update(&btchip_context_D.transactionHashWitness, + btchip_context_D.transactionBufferPointer, + value); } } @@ -102,19 +106,15 @@ unsigned long int transaction_get_varint(void) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(2); - result = - (unsigned long int)(*btchip_context_D.transactionBufferPointer) | - ((unsigned long int)(*(btchip_context_D.transactionBufferPointer + - 1)) - << 8); + result = (unsigned long int) (*btchip_context_D.transactionBufferPointer) | + ((unsigned long int) (*(btchip_context_D.transactionBufferPointer + 1)) << 8); transaction_offset_increase(2); return result; } else if (firstByte == 0xFE) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(4); - result = - btchip_read_u32(btchip_context_D.transactionBufferPointer, 0, 0); + result = btchip_read_u32(btchip_context_D.transactionBufferPointer, 0, 0); transaction_offset_increase(4); return result; } else { @@ -131,493 +131,461 @@ void transaction_parse(unsigned char parseMode) { BEGIN_TRY { TRY { for (;;) { - PRINTF("TX parse, state=%d\n", btchip_context_D.transactionContext.transactionState); + PRINTF("TX parse, state=%d\n", + btchip_context_D.transactionContext.transactionState); switch (btchip_context_D.transactionContext.transactionState) { - case BTCHIP_TRANSACTION_NONE: { - PRINTF("Init transaction parser\n"); - // Reset transaction state - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs = 0; - btchip_context_D.transactionContext - .transactionCurrentInputOutput = 0; - btchip_context_D.transactionContext.scriptRemaining = 0; - os_memset( - btchip_context_D.transactionContext.transactionAmount, - 0, sizeof(btchip_context_D.transactionContext - .transactionAmount)); - // TODO : transactionControlFid - // Reset hashes - blake256_Init(&btchip_context_D.transactionHashPrefix); - blake256_Init(&btchip_context_D.transactionHashWitness); - blake256_Init(&btchip_context_D.transactionHashAuthorization); - //cx_blake2b_init(&btchip_context_D.transactionHashPrefix, 256); - //cx_blake2b_init(&btchip_context_D.transactionHashWitness, 256); - - - // Parse the beginning of the transaction - // Version - check_transaction_available(4); - os_memmove(btchip_context_D.transactionVersion, - btchip_context_D.transactionBufferPointer, 4); - // decred "no witness" serialization type ORing - btchip_context_D.transactionBufferPointer[2] |= 1; - btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; // prefix only - transaction_offset_increase(4); - - btchip_context_D.transactionBufferPointer -= 4; - btchip_context_D.transactionDataRemaining += 4; - btchip_context_D.transactionBufferPointer[2] |= 3; - btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; // witness only - transaction_offset_increase(4); - - btchip_context_D.transactionHashOption = 0x05; // both prefix and witness hash - - - // Number of inputs - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs = - transaction_get_varint(); - btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; - - // Ready to proceed - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - - // no break is intentional - } + case BTCHIP_TRANSACTION_NONE: { + PRINTF("Init transaction parser\n"); + // Reset transaction state + btchip_context_D.transactionContext.transactionRemainingInputsOutputs = 0; + btchip_context_D.transactionContext.transactionCurrentInputOutput = 0; + btchip_context_D.transactionContext.scriptRemaining = 0; + os_memset(btchip_context_D.transactionContext.transactionAmount, + 0, + sizeof(btchip_context_D.transactionContext.transactionAmount)); + // TODO : transactionControlFid + // Reset hashes + blake256_Init(&btchip_context_D.transactionHashPrefix); + blake256_Init(&btchip_context_D.transactionHashWitness); + blake256_Init(&btchip_context_D.transactionHashAuthorization); + // cx_blake2b_init(&btchip_context_D.transactionHashPrefix, 256); + // cx_blake2b_init(&btchip_context_D.transactionHashWitness, 256); + + // Parse the beginning of the transaction + // Version + check_transaction_available(4); + os_memmove(btchip_context_D.transactionVersion, + btchip_context_D.transactionBufferPointer, + 4); + // decred "no witness" serialization type ORing + btchip_context_D.transactionBufferPointer[2] |= 1; + btchip_context_D.transactionHashOption = + TRANSACTION_HASH_FULL; // prefix only + transaction_offset_increase(4); + + btchip_context_D.transactionBufferPointer -= 4; + btchip_context_D.transactionDataRemaining += 4; + btchip_context_D.transactionBufferPointer[2] |= 3; + btchip_context_D.transactionHashOption = + TRANSACTION_HASH_WITNESS; // witness only + transaction_offset_increase(4); - case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { - unsigned char trustedInputFlag = 1; - PRINTF("Process input\n"); - if (btchip_context_D.transactionContext - .transactionRemainingInputsOutputs == 0) { - // No more inputs to hash, move forward + btchip_context_D.transactionHashOption = + 0x05; // both prefix and witness hash + + // Number of inputs + btchip_context_D.transactionContext.transactionRemainingInputsOutputs = + transaction_get_varint(); + btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; + + // Ready to proceed btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_DONE; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - PRINTF("Waiting for more data...\n"); - goto ok; - } - // Proceed with the next input - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - PRINTF("PARSE_MODE_TRUSTED_INPUT\n"); - check_transaction_available( - 37); // prevout : 32 hash + 4 index + 1 tree - transaction_offset_increase(37); + BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + + // no break is intentional } - if (parseMode == PARSE_MODE_SIGNATURE) { - PRINTF("PARSE_MODE_SIGNATURE\n"); - unsigned char trustedInputLength; - unsigned char trustedInput[0x38]; - unsigned char amount[8]; - unsigned char *savePointer; - - // Expect the trusted input flag and trusted input - // length - check_transaction_available(2); - switch (*btchip_context_D.transactionBufferPointer) { - case 0: - trustedInputFlag = 0; - break; - case 1: - trustedInputFlag = 1; - break; - - default: - PRINTF("Invalid trusted input flag\n"); - goto fail; + + case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { + unsigned char trustedInputFlag = 1; + PRINTF("Process input\n"); + if (btchip_context_D.transactionContext.transactionRemainingInputsOutputs == + 0) { + // No more inputs to hash, move forward + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_INPUT_HASHING_DONE; + continue; } - /* - trustedInputLength = - *(btchip_context_D.transactionBufferPointer + 1); - if (trustedInputLength > sizeof(trustedInput)) { - PRINTF("Trusted input too long\n"); - goto fail; + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + PRINTF("Waiting for more data...\n"); + goto ok; } - */ - - if (!trustedInputFlag) { - - if (!optionP2SHSkip2FA) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - - btchip_context_D.transactionBufferPointer++; - btchip_context_D.transactionDataRemaining--; + // Proceed with the next input + if (parseMode == PARSE_MODE_TRUSTED_INPUT) { + PRINTF("PARSE_MODE_TRUSTED_INPUT\n"); check_transaction_available( - 36); // prevout : 32 hash + 4 index - transaction_offset_increase(36); - PRINTF("Marking relaxed input\n"); - btchip_context_D.transactionContext.relaxed = 1; - /* - PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; - */ - } else { - trustedInputLength = *( - btchip_context_D.transactionBufferPointer + 1); - if ((trustedInputLength > sizeof(trustedInput)) || - (trustedInputLength < 8)) { - PRINTF("Invalid trusted input size\n"); - goto fail; - } - - check_transaction_available(2 + trustedInputLength); - cx_hmac_sha256( - N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), - btchip_context_D.transactionBufferPointer + 2, - trustedInputLength - 8, trustedInput, trustedInputLength); - if (btchip_secure_memcmp( - trustedInput, - btchip_context_D.transactionBufferPointer + - 2 + trustedInputLength - 8, - 8) != 0) { - PRINTF("Invalid signature\n"); - goto fail; - } - os_memmove( - trustedInput, - btchip_context_D.transactionBufferPointer + 2, - trustedInputLength - 8); - if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { - PRINTF("Failed to verify trusted input signature\n"); - goto fail; - } - else { - PRINTF("Good Signature\n"); + 37); // prevout : 32 hash + 4 index + 1 tree + transaction_offset_increase(37); + } + if (parseMode == PARSE_MODE_SIGNATURE) { + PRINTF("PARSE_MODE_SIGNATURE\n"); + unsigned char trustedInputLength; + unsigned char trustedInput[0x38]; + unsigned char amount[8]; + unsigned char *savePointer; + + // Expect the trusted input flag and trusted input + // length + check_transaction_available(2); + switch (*btchip_context_D.transactionBufferPointer) { + case 0: + trustedInputFlag = 0; + break; + case 1: + trustedInputFlag = 1; + break; + + default: + PRINTF("Invalid trusted input flag\n"); + goto fail; } - - // Update the hash with prevout data - savePointer = - btchip_context_D.transactionBufferPointer; //trusted input 01 /* - // Check if a P2SH script is used - if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == - 0) { - PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = - 0; + trustedInputLength = + *(btchip_context_D.transactionBufferPointer + 1); + if (trustedInputLength > sizeof(trustedInput)) { + PRINTF("Trusted input too long\n"); + goto fail; } */ - btchip_context_D.transactionBufferPointer = - trustedInput + 4; - PRINTF("Trusted input hash\n%.*H\n",36,btchip_context_D.transactionBufferPointer); - transaction_offset(36); - - btchip_context_D.transactionBufferPointer = - savePointer + (2 + trustedInputLength); - btchip_context_D.transactionDataRemaining -= - (2 + trustedInputLength); - - // add Decred tree - check_transaction_available(1); - transaction_offset_increase(1); - // Update the amount - - btchip_swap_bytes(amount, trustedInput + 40, 8); - if (transaction_amount_add_be( - btchip_context_D.transactionContext - .transactionAmount, - btchip_context_D.transactionContext - .transactionAmount, - amount)) { - PRINTF("Overflow\n"); - goto fail; + if (!trustedInputFlag) { + if (!optionP2SHSkip2FA) { + PRINTF("Untrusted input not authorized\n"); + goto fail; + } + + btchip_context_D.transactionBufferPointer++; + btchip_context_D.transactionDataRemaining--; + check_transaction_available(36); // prevout : 32 hash + 4 index + transaction_offset_increase(36); + PRINTF("Marking relaxed input\n"); + btchip_context_D.transactionContext.relaxed = 1; + /* + PRINTF("Clearing P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 0; + */ + } else { + trustedInputLength = + *(btchip_context_D.transactionBufferPointer + 1); + if ((trustedInputLength > sizeof(trustedInput)) || + (trustedInputLength < 8)) { + PRINTF("Invalid trusted input size\n"); + goto fail; + } + + check_transaction_available(2 + trustedInputLength); + cx_hmac_sha256(N_btchip.bkp.trustedinput_key, + sizeof(N_btchip.bkp.trustedinput_key), + btchip_context_D.transactionBufferPointer + 2, + trustedInputLength - 8, + trustedInput, + trustedInputLength); + if (btchip_secure_memcmp(trustedInput, + btchip_context_D.transactionBufferPointer + + 2 + trustedInputLength - 8, + 8) != 0) { + PRINTF("Invalid signature\n"); + goto fail; + } + os_memmove(trustedInput, + btchip_context_D.transactionBufferPointer + 2, + trustedInputLength - 8); + if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { + PRINTF("Failed to verify trusted input signature\n"); + goto fail; + } else { + PRINTF("Good Signature\n"); + } + + // Update the hash with prevout data + savePointer = + btchip_context_D.transactionBufferPointer; // trusted input 01 + /* + // Check if a P2SH script is used + if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == + 0) { + PRINTF("Clearing P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = + 0; + } + */ + btchip_context_D.transactionBufferPointer = trustedInput + 4; + PRINTF("Trusted input hash\n%.*H\n", + 36, + btchip_context_D.transactionBufferPointer); + transaction_offset(36); + + btchip_context_D.transactionBufferPointer = + savePointer + (2 + trustedInputLength); + btchip_context_D.transactionDataRemaining -= + (2 + trustedInputLength); + + // add Decred tree + check_transaction_available(1); + transaction_offset_increase(1); + + // Update the amount + + btchip_swap_bytes(amount, trustedInput + 40, 8); + if (transaction_amount_add_be( + btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.transactionContext.transactionAmount, + amount)) { + PRINTF("Overflow\n"); + goto fail; + } + + PRINTF("Adding amount\n%.*H\n", 8, (trustedInput + 40)); + PRINTF("New amount\n%.*H\n", + 8, + btchip_context_D.transactionContext.transactionAmount); } - - PRINTF("Adding amount\n%.*H\n",8,(trustedInput + 40)); - PRINTF("New amount\n%.*H\n",8,btchip_context_D.transactionContext.transactionAmount); } + // DIRTY: include utxo script len and script in witness hash + btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; - - } - // DIRTY: include utxo script len and script in witness hash - btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; - - // Read the script length - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - - if ((parseMode == PARSE_MODE_SIGNATURE) && - !trustedInputFlag) { - // Only proceeds if this is not to be signed - so length - // should be null - if (btchip_context_D.transactionContext - .scriptRemaining != 0) { - PRINTF("Request to sign relaxed input\n"); - if (!optionP2SHSkip2FA) { - goto fail; + // Read the script length + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); + PRINTF("Script to read " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + + if ((parseMode == PARSE_MODE_SIGNATURE) && !trustedInputFlag) { + // Only proceeds if this is not to be signed - so length + // should be null + if (btchip_context_D.transactionContext.scriptRemaining != 0) { + PRINTF("Request to sign relaxed input\n"); + if (!optionP2SHSkip2FA) { + goto fail; + } } } - } - PRINTF("NEXT_STATE\n"); - // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; + PRINTF("NEXT_STATE\n"); + // Move on + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - // no break is intentional - } - case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process input script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; + // no break is intentional } - // Scan for P2SH consumption - huge shortcut, but fine - // enough - // Also usable in SegWit mode - if (btchip_context_D.transactionContext.scriptRemaining == - 1) { - if (*btchip_context_D.transactionBufferPointer == - OP_CHECKMULTISIG) { - if (optionP2SHSkip2FA) { - PRINTF("Marking P2SH consumption\n"); - btchip_context_D.transactionContext - .consumeP2SH = 1; + case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process input script, remaining " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Scan for P2SH consumption - huge shortcut, but fine + // enough + // Also usable in SegWit mode + if (btchip_context_D.transactionContext.scriptRemaining == 1) { + if (*btchip_context_D.transactionBufferPointer == OP_CHECKMULTISIG) { + if (optionP2SHSkip2FA) { + PRINTF("Marking P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 1; + } + } else { + // When using the P2SH shortcut, all inputs must use + // P2SH + PRINTF("Disabling P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 0; } - } else { - // When using the P2SH shortcut, all inputs must use - // P2SH - PRINTF("Disabling P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; + transaction_offset_increase(1); + btchip_context_D.transactionContext.scriptRemaining--; } - transaction_offset_increase(1); - btchip_context_D.transactionContext.scriptRemaining--; - } - if (btchip_context_D.transactionContext.scriptRemaining == - 0) { - // restore full hash - btchip_context_D.transactionHashOption = 0x01; + if (btchip_context_D.transactionContext.scriptRemaining == 0) { + // restore full hash + btchip_context_D.transactionHashOption = 0x01; - if (parseMode == PARSE_MODE_SIGNATURE) { - btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; + if (parseMode == PARSE_MODE_SIGNATURE) { + btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; + } + // Sequence + check_transaction_available(4); + transaction_offset_increase(4); + // Move to next input + btchip_context_D.transactionContext.transactionRemainingInputsOutputs--; + btchip_context_D.transactionContext.transactionCurrentInputOutput++; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + continue; } - // Sequence - check_transaction_available(4); - transaction_offset_increase(4); - // Move to next input - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext - .transactionCurrentInputOutput++; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - continue; - } - // Save the last script byte for the P2SH check - dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext - .scriptRemaining - - 1 - ? btchip_context_D.transactionContext - .scriptRemaining - - 1 - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { - PRINTF("Input hashing done\n"); - if (parseMode == PARSE_MODE_SIGNATURE) { - - btchip_context_D.transactionContext - .transactionState = - BTCHIP_TRANSACTION_PRESIGN_READY; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; + // Save the last script byte for the P2SH check + dataAvailable = + (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext.scriptRemaining - 1 + ? btchip_context_D.transactionContext.scriptRemaining - 1 + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; + break; } - // Number of outputs - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs = - transaction_get_varint(); - btchip_context_D.transactionContext - .transactionCurrentInputOutput = 0; - PRINTF("Number of outputs : " DEBUG_LONG "\n", btchip_context_D.transactionContext .transactionRemainingInputsOutputs); - // Ready to proceed - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - - // no break is intentional - } - case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { - if (btchip_context_D.transactionContext - .transactionRemainingInputsOutputs == 0) { - // No more outputs to hash, move forward + case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { + PRINTF("Input hashing done\n"); + if (parseMode == PARSE_MODE_SIGNATURE) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PRESIGN_READY; + continue; + } + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Number of outputs + btchip_context_D.transactionContext.transactionRemainingInputsOutputs = + transaction_get_varint(); + btchip_context_D.transactionContext.transactionCurrentInputOutput = 0; + PRINTF( + "Number of outputs : " DEBUG_LONG "\n", + btchip_context_D.transactionContext.transactionRemainingInputsOutputs); + // Ready to proceed btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Amount - check_transaction_available(8); - if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && - (btchip_context_D.transactionContext - .transactionCurrentInputOutput == - btchip_context_D.transactionTargetInput)) { - // Save the amount - os_memmove(btchip_context_D.transactionContext - .transactionAmount, - btchip_context_D.transactionBufferPointer, - 8); - btchip_context_D.trustedInputProcessed = 1; - PRINTF("Input processed\n"); - } - transaction_offset_increase(8); + BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - // script version - check_transaction_available(2); - transaction_offset_increase(2); + // no break is intentional + } + case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { + if (btchip_context_D.transactionContext.transactionRemainingInputsOutputs == + 0) { + // No more outputs to hash, move forward + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; + continue; + } + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Amount + check_transaction_available(8); + if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && + (btchip_context_D.transactionContext.transactionCurrentInputOutput == + btchip_context_D.transactionTargetInput)) { + // Save the amount + os_memmove(btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.transactionBufferPointer, + 8); + btchip_context_D.trustedInputProcessed = 1; + PRINTF("Input processed\n"); + } + transaction_offset_increase(8); - // Read the script length - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); + // script version + check_transaction_available(2); + transaction_offset_increase(2); - PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; + // Read the script length + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); - // no break is intentional - } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process output script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - /* - // Special check if consuming a P2SH script - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - // Assume the full input script is sent in a single APDU, - then do the ghetto validation - if ((btchip_context_D.transactionBufferPointer[0] == - OP_HASH160) && - (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining - - 1] == OP_EQUAL)) { - PRINTF("Marking P2SH output\n"); - btchip_context_D.transactionContext.consumeP2SH = 1; - } - } - */ - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - if (btchip_context_D.transactionContext.scriptRemaining == - 0) { - // Move to next output - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext - .transactionCurrentInputOutput++; + PRINTF("Script to read " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + // Move on btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - continue; + BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; + + // no break is intentional } - dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext - .scriptRemaining - ? btchip_context_D.transactionContext - .scriptRemaining - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; + case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process output script, remaining " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + /* + // Special check if consuming a P2SH script + if (parseMode == PARSE_MODE_TRUSTED_INPUT) { + // Assume the full input script is sent in a single APDU, + then do the ghetto validation + if ((btchip_context_D.transactionBufferPointer[0] == + OP_HASH160) && + (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining + - 1] == OP_EQUAL)) { + PRINTF("Marking P2SH output\n"); + btchip_context_D.transactionContext.consumeP2SH = 1; + } + } + */ + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + if (btchip_context_D.transactionContext.scriptRemaining == 0) { + // Move to next output + btchip_context_D.transactionContext.transactionRemainingInputsOutputs--; + btchip_context_D.transactionContext.transactionCurrentInputOutput++; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; + continue; + } + dataAvailable = (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext.scriptRemaining + ? btchip_context_D.transactionContext.scriptRemaining + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; + break; } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { - PRINTF("Output hashing done\n"); - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; + case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { + PRINTF("Output hashing done\n"); + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Locktime + Expiration + check_transaction_available(4 + 4); + transaction_offset_increase(4 + 4); + + if (btchip_context_D.transactionDataRemaining == 0) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PARSED; + continue; + } else { + btchip_context_D.transactionHashOption = 0; + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); + btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PROCESS_EXTRA; + continue; + } } - // Locktime + Expiration - check_transaction_available(4+4); - transaction_offset_increase(4+4); - if (btchip_context_D.transactionDataRemaining == 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; - continue; - } else { - btchip_context_D.transactionHashOption = 0; - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); - btchip_context_D.transactionHashOption = - TRANSACTION_HASH_FULL; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PROCESS_EXTRA; - continue; - } - } + case BTCHIP_TRANSACTION_PROCESS_EXTRA: { + unsigned char dataAvailable; - case BTCHIP_TRANSACTION_PROCESS_EXTRA: { - unsigned char dataAvailable; + if (btchip_context_D.transactionContext.scriptRemaining == 0) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PARSED; + continue; + } - if (btchip_context_D.transactionContext.scriptRemaining == - 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; - continue; + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + + dataAvailable = (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext.scriptRemaining + ? btchip_context_D.transactionContext.scriptRemaining + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; + break; } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok + case BTCHIP_TRANSACTION_PARSED: { + PRINTF("Transaction parsed\n"); goto ok; } - dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext - .scriptRemaining - ? btchip_context_D.transactionContext - .scriptRemaining - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { + case BTCHIP_TRANSACTION_PRESIGN_READY: { + PRINTF("Presign ready\n"); goto ok; } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case BTCHIP_TRANSACTION_PARSED: { - PRINTF("Transaction parsed\n"); - goto ok; - } - - case BTCHIP_TRANSACTION_PRESIGN_READY: { - PRINTF("Presign ready\n"); - goto ok; - } - - case BTCHIP_TRANSACTION_SIGN_READY: { - PRINTF("Sign ready\n"); - goto ok; - } + case BTCHIP_TRANSACTION_SIGN_READY: { + PRINTF("Sign ready\n"); + goto ok; + } } } @@ -628,8 +596,7 @@ void transaction_parse(unsigned char parseMode) { } CATCH_OTHER(e) { PRINTF("Transaction parse - surprise fail\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); THROW(e); } diff --git a/src/btchip_transaction.h b/src/btchip_transaction.h index 6005abc..cc6e20d 100644 --- a/src/btchip_transaction.h +++ b/src/btchip_transaction.h @@ -1,44 +1,40 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #ifndef _BTCHIP_TRANSACTION_H_ #define _BTCHIP_TRANSACTION_H_ #include "btchip_secure_value.h" -#define TRANSACTION_HASH_NONE 0x00 -#define TRANSACTION_HASH_FULL 0x01 +#define TRANSACTION_HASH_NONE 0x00 +#define TRANSACTION_HASH_FULL 0x01 #define TRANSACTION_HASH_AUTHORIZATION 0x02 -#define TRANSACTION_HASH_BOTH 0x03 -#define TRANSACTION_HASH_WITNESS 0x04 +#define TRANSACTION_HASH_BOTH 0x03 +#define TRANSACTION_HASH_WITNESS 0x04 #define PARSE_MODE_TRUSTED_INPUT 0x01 -#define PARSE_MODE_SIGNATURE 0x02 +#define PARSE_MODE_SIGNATURE 0x02 void transaction_parse(unsigned char parseMode); // target = a + b -unsigned char transaction_amount_add_be(unsigned char *target, - unsigned char *a, - unsigned char *b); +unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, unsigned char *b); // target = a - b -unsigned char transaction_amount_sub_be(unsigned char *target, - unsigned char *a, - unsigned char *b); +unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b); #endif /* _BTCHIP_TRANSACTION_H_ */ diff --git a/src/main.c b/src/main.c index 1b10ec3..083212c 100644 --- a/src/main.c +++ b/src/main.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "os.h" #include "cx.h" @@ -28,56 +28,256 @@ #include "ux.h" #define __NAME3(a, b, c) a##b##c -#define NAME3(a, b, c) __NAME3(a, b, c) +#define NAME3(a, b, c) __NAME3(a, b, c) bagl_element_t tmp_element; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10 +#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10 #define BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH 8 -#define MAX_CHAR_PER_LINE 25 - -#define COLOR_BG_1 0xF9F9F9 -#define COLOR_APP COIN_COLOR_HDR // bitcoin 0xFCB653 -#define COLOR_APP_LIGHT COIN_COLOR_DB // bitcoin 0xFEDBA9 -#define COLOR_BLACK 0x000000 -#define COLOR_WHITE 0xFFFFFF -#define COLOR_GRAY 0x999999 +#define MAX_CHAR_PER_LINE 25 + +#define COLOR_BG_1 0xF9F9F9 +#define COLOR_APP COIN_COLOR_HDR // bitcoin 0xFCB653 +#define COLOR_APP_LIGHT COIN_COLOR_DB // bitcoin 0xFEDBA9 +#define COLOR_BLACK 0x000000 +#define COLOR_WHITE 0xFFFFFF +#define COLOR_GRAY 0x999999 #define COLOR_LIGHT_GRAY 0xEEEEEE -#define UI_NANOS_BACKGROUND() {{BAGL_RECTANGLE,0,0,0,128,32,0,0,BAGL_FILL,0,COLOR_WHITE,0,0},NULL,0,0,0,NULL,NULL,NULL} -#define UI_NANOS_ICON_LEFT(userid, glyph) {{BAGL_ICON,userid,3,12,7,7,0,0,0,COLOR_WHITE,0,0,glyph},NULL,0,0,0,NULL,NULL,NULL} -#define UI_NANOS_ICON_RIGHT(userid, glyph) {{BAGL_ICON,userid,117,13,8,6,0,0,0,COLOR_WHITE,0,0,glyph},NULL,0,0,0,NULL,NULL,NULL} -#define UI_NANOS_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,0},(char *)text,0,0,0,NULL,NULL,NULL} +#define UI_NANOS_BACKGROUND() \ + { \ + {BAGL_RECTANGLE, 0, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0, COLOR_WHITE, 0, 0}, NULL, 0, 0, 0, \ + NULL, NULL, NULL \ + } +#define UI_NANOS_ICON_LEFT(userid, glyph) \ + { \ + {BAGL_ICON, userid, 3, 12, 7, 7, 0, 0, 0, COLOR_WHITE, 0, 0, glyph}, NULL, 0, 0, 0, NULL, \ + NULL, NULL \ + } +#define UI_NANOS_ICON_RIGHT(userid, glyph) \ + { \ + {BAGL_ICON, userid, 117, 13, 8, 6, 0, 0, 0, COLOR_WHITE, 0, 0, glyph}, NULL, 0, 0, 0, \ + NULL, NULL, NULL \ + } +#define UI_NANOS_TEXT(userid, x, y, w, text, font) \ + { \ + {BAGL_LABELINE, \ + userid, \ + x, \ + y, \ + w, \ + 12, \ + 0, \ + 0, \ + 0, \ + COLOR_WHITE, \ + 0, \ + font | BAGL_FONT_ALIGNMENT_CENTER, \ + 0}, \ + (char *) text, 0, 0, 0, NULL, NULL, NULL \ + } // Only one scrolling text per screen can be displayed -#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0x80|10,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,26},(char *)text,0,0,0,NULL,NULL,NULL} - -#define UI_BLUE_BACKGROUND(title) {{BAGL_RECTANGLE, 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1,COLOR_BLACK, 0, 0},NULL,0,0,0,NULL,NULL,NULL}, \ -{{BAGL_RECTANGLE, 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0, 0},NULL,0,0,0,NULL,NULL,NULL}, \ -{{BAGL_LABELINE, 0x01, 0, 45, 320, 30, 0, 0, BAGL_FILL, COLOR_WHITE, COLOR_APP, BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX | BAGL_FONT_ALIGNMENT_CENTER, 0},title,0,0,0,NULL,NULL,NULL} -#define UI_BLUE_BUTTON_SETTINGS(setting_cb) {{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 0, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_SETTINGS, 0, COLOR_APP, COLOR_WHITE, setting_cb, NULL, NULL} -#define UI_BLUE_BUTTON_GO_BACK(back_cb) {{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 0, 19, 50, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE, 0 }, BAGL_FONT_SYMBOLS_0_LEFT, 0, COLOR_APP, COLOR_WHITE, back_cb, NULL, NULL} -#define UI_BLUE_ICON(userid, x, y, width, height, icon, bg_color){{BAGL_ICON, userid, x, y, width, height, 0, 0, BAGL_FILL, 0, bg_color, 0, 0},icon,0,0,0,NULL,NULL,NULL} -// Toggle icon should be set/updated within a preprocessor -#define UI_BLUE_TOGGLE(x, y, bg_color) {{BAGL_ICON, 0x01, x, y, 320, 18, 0, 0, BAGL_FILL, COLOR_BLACK, bg_color, 0, 0 }, NULL, 0, 0, 0, NULL, NULL, NULL} -#define UI_BLUE_TOUCHZONE(x, y, x_max, y_max, tap_cb, out_cb, over_cb) {{BAGL_NONE|BAGL_FLAG_TOUCHABLE, 0x00, x, y, x_max, y_max, 0, 0, BAGL_FILL, COLOR_WHITE, COLOR_BLACK, 0 , 0}, NULL, 0, COLOR_LIGHT_GRAY, COLOR_BLACK, tap_cb, out_cb, over_cb} -#define UI_BLUE_BUTTON_EXIT(exit_cb) {{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, 0x00, 264, 19, 56, 44, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP_LIGHT, BAGL_FONT_SYMBOLS_0 | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, 0}, BAGL_FONT_SYMBOLS_0_DASHBOARD, 0, COLOR_APP, COLOR_WHITE, exit_cb, NULL, NULL} -// Displays standard interface for approval: 2 buttons at the bottom of the screen, one to cancel and one to proceed -#define UI_BLUE_BUTTONS_REJECT_OR_CONFIRM(reject_text, confirm_text, reject_cb, confirm_cb) {{BAGL_RECTANGLE|BAGL_FLAG_TOUCHABLE,0x00,40,414,115,36,0,18,BAGL_FILL,0xCCCCCC,COLOR_BG_1,BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE,0},reject_text,0,0xB7B7B7,COLOR_BG_1,reject_cb,NULL,NULL},{{BAGL_RECTANGLE|BAGL_FLAG_TOUCHABLE,0x00,165,414,115,36,0,18,BAGL_FILL,0x41ccb4,COLOR_BG_1,BAGL_FONT_OPEN_SANS_REGULAR_11_14PX|BAGL_FONT_ALIGNMENT_CENTER|BAGL_FONT_ALIGNMENT_MIDDLE,0},confirm_text,0,0x3ab7a2,COLOR_BG_1,confirm_cb,NULL,NULL} -#define UI_BLUE_TEXT(userid, x, y, w, text, font, flags, text_color, bg_color) {{BAGL_LABELINE,userid,x,y,w,30,0,0,BAGL_FILL,text_color,bg_color,font|flags,0},(char *)text,0,0,0,NULL,NULL,NULL} +#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) \ + { \ + {BAGL_LABELINE, \ + userid, \ + x, \ + y, \ + w, \ + 12, \ + 0x80 | 10, \ + 0, \ + 0, \ + COLOR_WHITE, \ + 0, \ + font | BAGL_FONT_ALIGNMENT_CENTER, \ + 26}, \ + (char *) text, 0, 0, 0, NULL, NULL, NULL \ + } +#define UI_BLUE_BACKGROUND(title) \ + {{BAGL_RECTANGLE, 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BLACK, 0, 0}, \ + NULL, \ + 0, \ + 0, \ + 0, \ + NULL, \ + NULL, \ + NULL}, \ + {{BAGL_RECTANGLE, 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0, 0}, \ + NULL, \ + 0, \ + 0, \ + 0, \ + NULL, \ + NULL, \ + NULL}, \ + { \ + {BAGL_LABELINE, \ + 0x01, \ + 0, \ + 45, \ + 320, \ + 30, \ + 0, \ + 0, \ + BAGL_FILL, \ + COLOR_WHITE, \ + COLOR_APP, \ + BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX | BAGL_FONT_ALIGNMENT_CENTER, \ + 0}, \ + title, 0, 0, 0, NULL, NULL, NULL \ + } +#define UI_BLUE_BUTTON_SETTINGS(setting_cb) \ + { \ + {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ + 0x00, \ + 0, \ + 19, \ + 56, \ + 44, \ + 0, \ + 0, \ + BAGL_FILL, \ + COLOR_APP, \ + COLOR_APP_LIGHT, \ + BAGL_FONT_SYMBOLS_0 | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, \ + 0}, \ + BAGL_FONT_SYMBOLS_0_SETTINGS, 0, COLOR_APP, COLOR_WHITE, setting_cb, NULL, NULL \ + } +#define UI_BLUE_BUTTON_GO_BACK(back_cb) \ + { \ + {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ + 0x00, \ + 0, \ + 19, \ + 50, \ + 44, \ + 0, \ + 0, \ + BAGL_FILL, \ + COLOR_APP, \ + COLOR_APP_LIGHT, \ + BAGL_FONT_SYMBOLS_0 | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, \ + 0}, \ + BAGL_FONT_SYMBOLS_0_LEFT, 0, COLOR_APP, COLOR_WHITE, back_cb, NULL, NULL \ + } +#define UI_BLUE_ICON(userid, x, y, width, height, icon, bg_color) \ + { \ + {BAGL_ICON, userid, x, y, width, height, 0, 0, BAGL_FILL, 0, bg_color, 0, 0}, icon, 0, 0, \ + 0, NULL, NULL, NULL \ + } +// Toggle icon should be set/updated within a preprocessor +#define UI_BLUE_TOGGLE(x, y, bg_color) \ + { \ + {BAGL_ICON, 0x01, x, y, 320, 18, 0, 0, BAGL_FILL, COLOR_BLACK, bg_color, 0, 0}, NULL, 0, \ + 0, 0, NULL, NULL, NULL \ + } +#define UI_BLUE_TOUCHZONE(x, y, x_max, y_max, tap_cb, out_cb, over_cb) \ + { \ + {BAGL_NONE | BAGL_FLAG_TOUCHABLE, \ + 0x00, \ + x, \ + y, \ + x_max, \ + y_max, \ + 0, \ + 0, \ + BAGL_FILL, \ + COLOR_WHITE, \ + COLOR_BLACK, \ + 0, \ + 0}, \ + NULL, 0, COLOR_LIGHT_GRAY, COLOR_BLACK, tap_cb, out_cb, over_cb \ + } +#define UI_BLUE_BUTTON_EXIT(exit_cb) \ + { \ + {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ + 0x00, \ + 264, \ + 19, \ + 56, \ + 44, \ + 0, \ + 0, \ + BAGL_FILL, \ + COLOR_APP, \ + COLOR_APP_LIGHT, \ + BAGL_FONT_SYMBOLS_0 | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, \ + 0}, \ + BAGL_FONT_SYMBOLS_0_DASHBOARD, 0, COLOR_APP, COLOR_WHITE, exit_cb, NULL, NULL \ + } +// Displays standard interface for approval: 2 buttons at the bottom of the screen, one to cancel +// and one to proceed +#define UI_BLUE_BUTTONS_REJECT_OR_CONFIRM(reject_text, confirm_text, reject_cb, confirm_cb) \ + {{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ + 0x00, \ + 40, \ + 414, \ + 115, \ + 36, \ + 0, \ + 18, \ + BAGL_FILL, \ + 0xCCCCCC, \ + COLOR_BG_1, \ + BAGL_FONT_OPEN_SANS_REGULAR_11_14PX | BAGL_FONT_ALIGNMENT_CENTER | \ + BAGL_FONT_ALIGNMENT_MIDDLE, \ + 0}, \ + reject_text, \ + 0, \ + 0xB7B7B7, \ + COLOR_BG_1, \ + reject_cb, \ + NULL, \ + NULL}, \ + { \ + {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ + 0x00, \ + 165, \ + 414, \ + 115, \ + 36, \ + 0, \ + 18, \ + BAGL_FILL, \ + 0x41ccb4, \ + COLOR_BG_1, \ + BAGL_FONT_OPEN_SANS_REGULAR_11_14PX | BAGL_FONT_ALIGNMENT_CENTER | \ + BAGL_FONT_ALIGNMENT_MIDDLE, \ + 0}, \ + confirm_text, 0, 0x3ab7a2, COLOR_BG_1, confirm_cb, NULL, NULL \ + } +#define UI_BLUE_TEXT(userid, x, y, w, text, font, flags, text_color, bg_color) \ + { \ + {BAGL_LABELINE, \ + userid, \ + x, \ + y, \ + w, \ + 30, \ + 0, \ + 0, \ + BAGL_FILL, \ + text_color, \ + bg_color, \ + font | flags, \ + 0}, \ + (char *) text, 0, 0, 0, NULL, NULL, NULL \ + } #if defined(TARGET_BLUE) #include "qrcodegen.h" union { struct { - char addressSummary[40]; // beginning of the output address ... end of - char fullAmount[65]; // full amount + char addressSummary[40]; // beginning of the output address ... end of + char fullAmount[65]; // full amount char fullAddress[65]; // the address - char feesAmount[40]; // fees + char feesAmount[40]; // fees char output_numbering[10]; } tmp; @@ -89,15 +289,16 @@ union { } tmpqr; struct { - // A bip44 path contains 5 elements, which max length in ascii is 10 char + optional quote "'" + "/" + \0" - char derivation_path [MAX_DERIV_PATH_ASCII_LENGTH]; + // A bip44 path contains 5 elements, which max length in ascii is 10 char + optional quote + // "'" + "/" + \0" + char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; } tmp_warning; - unsigned int dummy; // ensure the whole vars is aligned for the CM0 to - // operate correctly + unsigned int dummy; // ensure the whole vars is aligned for the CM0 to + // operate correctly } vars; -void load_qr_code(unsigned char *data){ +void load_qr_code(unsigned char *data) { // must assert spi buffer is longer than the requested qrcode len. // sizeof(data and temp buffer) >= // qrcodegen_BUFFER_LEN_FOR_VERSION(guessed_qrcode_version) @@ -105,14 +306,18 @@ void load_qr_code(unsigned char *data){ // encode the address as a QRcode os_memset(&vars.tmpqr, 0, sizeof(vars.tmpqr)); // use G_io_seproxyhal_spi_buffer as - if (qrcodegen_encodeBinary( - data, strlen(data), - G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), - // the edge qrcode size will be discarded when drawing - &vars.tmpqr.qrcode, sizeof(vars.tmpqr.qrcode), qrcodegen_Ecc_LOW, - qrcodegen_VERSION_MIN, - 3, // buffer is not designed to handle more than version 3 - qrcodegen_Mask_AUTO, 0)) { + if (qrcodegen_encodeBinary(data, + strlen(data), + G_io_seproxyhal_spi_buffer, + sizeof(G_io_seproxyhal_spi_buffer), + // the edge qrcode size will be discarded when drawing + &vars.tmpqr.qrcode, + sizeof(vars.tmpqr.qrcode), + qrcodegen_Ecc_LOW, + qrcodegen_VERSION_MIN, + 3, // buffer is not designed to handle more than version 3 + qrcodegen_Mask_AUTO, + 0)) { vars.tmpqr.icon_details.width = vars.tmpqr.qrcode[0]; vars.tmpqr.icon_details.height = vars.tmpqr.qrcode[0]; vars.tmpqr.icon_details.bpp = 1; @@ -129,11 +334,11 @@ void load_qr_code(unsigned char *data){ unsigned int map_color(unsigned int color) { switch (color) { - case COLOR_APP: - return G_coin_config->color_header; + case COLOR_APP: + return G_coin_config->color_header; - case COLOR_APP_LIGHT: - return G_coin_config->color_dashboard; + case COLOR_APP_LIGHT: + return G_coin_config->color_dashboard; } return color; } @@ -152,13 +357,13 @@ union { // char addressSummary[40]; // beginning of the output address ... end // of - char fullAddress[43]; // the address - char fullAmount[20]; // full amount - char feesAmount[20]; // fees + char fullAddress[43]; // the address + char fullAmount[20]; // full amount + char feesAmount[20]; // fees } tmp; struct { - char derivation_path [MAX_DERIV_PATH_ASCII_LENGTH]; + char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; } tmp_warning; /* @@ -176,10 +381,8 @@ union { unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e); -unsigned int -io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e); -unsigned int -io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e); +unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e); +unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_address_blue(const bagl_element_t *e); @@ -195,16 +398,16 @@ ux_state_t G_ux; bolos_ux_params_t G_ux_params; #else ux_state_t ux; -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 // display stepped screens unsigned int ux_step; unsigned int ux_step_count; -uint8_t ux_loop_over_curr_element; // Nano S only +uint8_t ux_loop_over_curr_element; // Nano S only const bagl_element_t *ui_menu_item_out_over(const bagl_element_t *e) { // the selection rectangle is after the none|touchable - e = (const bagl_element_t *)(((unsigned int)e) + sizeof(bagl_element_t)); + e = (const bagl_element_t *) (((unsigned int) e) + sizeof(bagl_element_t)); return e; } @@ -223,72 +426,123 @@ const bagl_element_t ui_idle_blue[] = { UI_BLUE_BACKGROUND(NULL), UI_BLUE_BUTTON_SETTINGS(io_seproxyhal_touch_settings), UI_BLUE_BUTTON_EXIT(io_seproxyhal_touch_exit), - UI_BLUE_TEXT(0, 0, 270, 320, "Open your wallet", BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 308, 320, "Connect your Ledger Blue and open your", BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 331, 320, "preferred wallet to view your accounts.", BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 450, 320, "Validation requests will show automatically.", BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_GRAY, COLOR_BG_1) + UI_BLUE_TEXT(0, + 0, + 270, + 320, + "Open your wallet", + BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 308, + 320, + "Connect your Ledger Blue and open your", + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 331, + 320, + "preferred wallet to view your accounts.", + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 450, + 320, + "Validation requests will show automatically.", + BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_GRAY, + COLOR_BG_1) }; -unsigned int ui_idle_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int ui_idle_blue_button(unsigned int button_mask, unsigned int button_mask_counter) { return 0; } -const bagl_element_t * ui_settings_blue_toggle_pubKeyRequestRestriction(const bagl_element_t * e) { +const bagl_element_t *ui_settings_blue_toggle_pubKeyRequestRestriction(const bagl_element_t *e) { // swap setting and request redraw of settings elements - uint8_t setting = N_btchip.pubKeyRequestRestriction?0:1; - nvm_write(&N_btchip.pubKeyRequestRestriction, (void*)&setting, sizeof(uint8_t)); + uint8_t setting = N_btchip.pubKeyRequestRestriction ? 0 : 1; + nvm_write(&N_btchip.pubKeyRequestRestriction, (void *) &setting, sizeof(uint8_t)); // only refresh settings mutable drawn elements UX_REDISPLAY_IDX(7); // won't redisplay the bagl_none return 0; } // don't perform any draw/color change upon finger event over settings -const bagl_element_t* ui_settings_out_over(const bagl_element_t* e) { - return NULL; +const bagl_element_t *ui_settings_out_over(const bagl_element_t *e) { + return NULL; } -unsigned int ui_settings_back_callback(const bagl_element_t* e) { - // go back to idle - ui_idle(); - return 0; +unsigned int ui_settings_back_callback(const bagl_element_t *e) { + // go back to idle + ui_idle(); + return 0; } const bagl_element_t ui_settings_blue[] = { UI_BLUE_BACKGROUND("SETTINGS"), UI_BLUE_BUTTON_GO_BACK(ui_settings_back_callback), - UI_BLUE_TEXT(0, 30, 105, 160, "Public key export", BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 30, 126, 260, "Enable to approve export requests manually", BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_GRAY, COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, 78, 320, 68, ui_settings_blue_toggle_pubKeyRequestRestriction, ui_settings_out_over, ui_settings_out_over), - UI_BLUE_TOGGLE(258, 98, COLOR_BG_1) -}; -const bagl_element_t * ui_settings_blue_prepro(const bagl_element_t * e) { - copy_element_and_map_coin_colors(e); - // none elements are skipped - if ((e->component.type&(~BAGL_FLAG_TOUCHABLE)) == BAGL_NONE) { - return 0; - } - // swap icon buffer to be displayed depending on if corresponding setting is enabled or not. - if (e->component.userid) { - switch(e->component.userid) { - case 0x01: - // swap icon content - if (N_btchip.pubKeyRequestRestriction) { - tmp_element.text = &C_blue_icon_toggle_set; - } - else { - tmp_element.text = &C_blue_icon_toggle_reset; + UI_BLUE_TEXT(0, + 30, + 105, + 160, + "Public key export", + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 30, + 126, + 260, + "Enable to approve export requests manually", + BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_GRAY, + COLOR_BG_1), + UI_BLUE_TOUCHZONE(0, + 78, + 320, + 68, + ui_settings_blue_toggle_pubKeyRequestRestriction, + ui_settings_out_over, + ui_settings_out_over), + UI_BLUE_TOGGLE(258, 98, COLOR_BG_1)}; +const bagl_element_t *ui_settings_blue_prepro(const bagl_element_t *e) { + copy_element_and_map_coin_colors(e); + // none elements are skipped + if ((e->component.type & (~BAGL_FLAG_TOUCHABLE)) == BAGL_NONE) { + return 0; + } + // swap icon buffer to be displayed depending on if corresponding setting is enabled or not. + if (e->component.userid) { + switch (e->component.userid) { + case 0x01: + // swap icon content + if (N_btchip.pubKeyRequestRestriction) { + tmp_element.text = &C_blue_icon_toggle_set; + } else { + tmp_element.text = &C_blue_icon_toggle_reset; + } + break; } - break; } - } - return &tmp_element; + return &tmp_element; } unsigned int ui_settings_blue_button(unsigned int button_mask, unsigned int button_mask_counter) { - return 0; + return 0; } -#endif // #if defined(TARGET_BLUE) +#endif // #if defined(TARGET_BLUE) #if defined(TARGET_NANOS) @@ -297,15 +551,14 @@ const ux_menu_entry_t menu_settings[]; // change the setting void menu_settings_pubKeyRequestRestriction_change(unsigned int enabled) { - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); + nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &enabled, 1); // go back to the menu entry UX_MENU_DISPLAY(0, menu_main, NULL); } const ux_menu_entry_t menu_settings_pubKeyRequestRestriction[] = { - {NULL, menu_settings_pubKeyRequestRestriction_change, 1, NULL, "Manual approval", NULL, 0, 0}, - {NULL, menu_settings_pubKeyRequestRestriction_change, 0, NULL, "Auto approval", NULL, 0, 0}, - UX_MENU_END -}; + {NULL, menu_settings_pubKeyRequestRestriction_change, 1, NULL, "Manual approval", NULL, 0, 0}, + {NULL, menu_settings_pubKeyRequestRestriction_change, 0, NULL, "Auto approval", NULL, 0, 0}, + UX_MENU_END}; const ux_menu_entry_t menu_settings[] = { {menu_settings_pubKeyRequestRestriction, NULL, 0, NULL, "Public keys", "export approval", 0, 0}, {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, @@ -318,14 +571,14 @@ const ux_menu_entry_t menu_about[] = { const ux_menu_entry_t menu_main[] = { //{NULL, NULL, 0, &NAME3(C_nanos_badge_, COINID, ), "Use wallet to", "view - //accounts", 33, 12}, + // accounts", 33, 12}, {NULL, NULL, 0, NULL, "Use wallet to", "view accounts", 0, 0}, {menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0}, {menu_about, NULL, 0, NULL, "About", NULL, 0, 0}, {NULL, os_sched_exit, 0, &C_nanos_icon_dashboard, "Quit app", NULL, 50, 29}, UX_MENU_END}; -#endif // #if defined(TARGET_NANOS) +#endif // #if defined(TARGET_NANOS) #if defined(TARGET_BLUE) // reuse vars.tmp.addressSummary for each line content @@ -335,29 +588,122 @@ callback_t ui_details_back_callback; const char *ui_details_title; const char *ui_details_content; -const bagl_element_t * -ui_details_blue_back_callback(const bagl_element_t *element) { +const bagl_element_t *ui_details_blue_back_callback(const bagl_element_t *element) { ui_details_back_callback(); return 0; } -const bagl_element_t ui_details_blue[] = { - UI_BLUE_BACKGROUND(NULL), - UI_BLUE_BUTTON_GO_BACK(ui_details_blue_back_callback), - UI_BLUE_TEXT(0, 30, 106, 320, "VALUE", BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_GRAY, COLOR_BG_1), - UI_BLUE_TEXT(0x10, 30, 136, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x11, 30, 159, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x12, 30, 182, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x13, 30, 205, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x14, 30, 228, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x15, 30, 251, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x16, 30, 274, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x17, 30, 297, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x18, 30, 320, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_BLACK, COLOR_BG_1), - //"..." at the end if too much - UI_BLUE_TEXT(0x19, 30, 343, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_GRAY, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 450, 320, "Review the whole value before continuing.", BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_GRAY, COLOR_BG_1) -}; +const bagl_element_t ui_details_blue[] = {UI_BLUE_BACKGROUND(NULL), + UI_BLUE_BUTTON_GO_BACK(ui_details_blue_back_callback), + UI_BLUE_TEXT(0, + 30, + 106, + 320, + "VALUE", + BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_GRAY, + COLOR_BG_1), + UI_BLUE_TEXT(0x10, + 30, + 136, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x11, + 30, + 159, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x12, + 30, + 182, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x13, + 30, + 205, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x14, + 30, + 228, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x15, + 30, + 251, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x16, + 30, + 274, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x17, + 30, + 297, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x18, + 30, + 320, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_BLACK, + COLOR_BG_1), + //"..." at the end if too much + UI_BLUE_TEXT(0x19, + 30, + 343, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_GRAY, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 450, + 320, + "Review the whole value before continuing.", + BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_GRAY, + COLOR_BG_1)}; const bagl_element_t *ui_details_blue_prepro(const bagl_element_t *element) { copy_element_and_map_coin_colors(element); @@ -369,11 +715,9 @@ const bagl_element_t *ui_details_blue_prepro(const bagl_element_t *element) { if (length >= (element->component.userid & 0xF) * MAX_CHAR_PER_LINE) { os_memset(vars.tmp.addressSummary, 0, MAX_CHAR_PER_LINE + 1); os_memmove(vars.tmp.addressSummary, - ui_details_content + (element->component.userid & 0xF) * - MAX_CHAR_PER_LINE, - MIN(length - (element->component.userid & 0xF) * - MAX_CHAR_PER_LINE, - MAX_CHAR_PER_LINE)); + ui_details_content + (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, + MIN(length - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, + MAX_CHAR_PER_LINE)); return 1; } // nothing to draw for this line @@ -382,13 +726,11 @@ const bagl_element_t *ui_details_blue_prepro(const bagl_element_t *element) { return &tmp_element; } -unsigned int ui_details_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int ui_details_blue_button(unsigned int button_mask, unsigned int button_mask_counter) { return 0; } -void ui_details_init(const char *title, const char *content, - callback_t back_callback) { +void ui_details_init(const char *title, const char *content, callback_t back_callback) { ui_details_title = title; ui_details_content = content; ui_details_back_callback = back_callback; @@ -405,8 +747,7 @@ const bagl_element_t *ui_transaction_blue_ok_callback(const bagl_element_t *e) { return ui_transaction_blue_ok(e); } -const bagl_element_t * -ui_transaction_blue_cancel_callback(const bagl_element_t *e) { +const bagl_element_t *ui_transaction_blue_cancel_callback(const bagl_element_t *e) { return ui_transaction_blue_cancel(e); } @@ -463,84 +804,239 @@ const char *const ui_transaction_blue_details_name[][5] = { }; const bagl_element_t *ui_transaction_blue_1_details(const bagl_element_t *e) { - if (strlen(ui_transaction_blue_values[0]) * - BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= + if (strlen(ui_transaction_blue_values[0]) * BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= 160) { // display details screen - ui_details_init( - ui_transaction_blue_details_name[G_ui_transaction_blue_state][0], - ui_transaction_blue_values[0], ui_transaction_blue_init); + ui_details_init(ui_transaction_blue_details_name[G_ui_transaction_blue_state][0], + ui_transaction_blue_values[0], + ui_transaction_blue_init); } return 0; }; const bagl_element_t *ui_transaction_blue_2_details(const bagl_element_t *e) { - if (strlen(ui_transaction_blue_values[1]) * - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= + if (strlen(ui_transaction_blue_values[1]) * BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= 160) { - ui_details_init( - ui_transaction_blue_details_name[G_ui_transaction_blue_state][1], - ui_transaction_blue_values[1], ui_transaction_blue_init); + ui_details_init(ui_transaction_blue_details_name[G_ui_transaction_blue_state][1], + ui_transaction_blue_values[1], + ui_transaction_blue_init); } return 0; }; const bagl_element_t *ui_transaction_blue_3_details(const bagl_element_t *e) { - if (strlen(ui_transaction_blue_values[2]) * - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= + if (strlen(ui_transaction_blue_values[2]) * BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= 160) { - ui_details_init( - ui_transaction_blue_details_name[G_ui_transaction_blue_state][2], - ui_transaction_blue_values[2], ui_transaction_blue_init); + ui_details_init(ui_transaction_blue_details_name[G_ui_transaction_blue_state][2], + ui_transaction_blue_values[2], + ui_transaction_blue_init); } return 0; }; const bagl_element_t ui_transaction_blue[] = { UI_BLUE_BACKGROUND(NULL), - UI_BLUE_TEXT(0, 30, 106, 320, "VALUE", BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, BAGL_FONT_ALIGNMENT_LEFT, COLOR_GRAY, COLOR_BG_1), + UI_BLUE_TEXT(0, + 30, + 106, + 320, + "VALUE", + BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, + BAGL_FONT_ALIGNMENT_LEFT, + COLOR_GRAY, + COLOR_BG_1), UI_BLUE_ICON(0x40, 30, 98, 50, 50, &C_blue_badge_transaction, COLOR_BG_1), // becomes a line in preprocessor - UI_BLUE_TEXT(0x50, 100, 117, 320, NULL, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 100, 138, 320, "Check and confirm values", BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, 0, COLOR_GRAY, COLOR_BG_1), + UI_BLUE_TEXT(0x50, + 100, + 117, + 320, + NULL, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + 0, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 100, + 138, + 320, + "Check and confirm values", + BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, + 0, + COLOR_GRAY, + COLOR_BG_1), // First detail zone - UI_BLUE_TEXT(0x70, 30, 196, 100, NULL, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0, COLOR_BLACK, COLOR_BG_1), + UI_BLUE_TEXT(0x70, + 30, + 196, + 100, + NULL, + BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, + 0, + COLOR_BLACK, + COLOR_BG_1), // x-18 when ... - UI_BLUE_TEXT(0x10, 130, 200, 160, NULL, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_RIGHT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x20, 284, 196, 6, BAGL_FONT_SYMBOLS_0_MINIRIGHT, BAGL_FONT_SYMBOLS_0, BAGL_FONT_ALIGNMENT_RIGHT, COLOR_GRAY, COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, 168, 320, 48, ui_transaction_blue_1_details, ui_menu_item_out_over, ui_menu_item_out_over), + UI_BLUE_TEXT(0x10, + 130, + 200, + 160, + NULL, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_RIGHT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x20, + 284, + 196, + 6, + BAGL_FONT_SYMBOLS_0_MINIRIGHT, + BAGL_FONT_SYMBOLS_0, + BAGL_FONT_ALIGNMENT_RIGHT, + COLOR_GRAY, + COLOR_BG_1), + UI_BLUE_TOUCHZONE(0, + 168, + 320, + 48, + ui_transaction_blue_1_details, + ui_menu_item_out_over, + ui_menu_item_out_over), {{BAGL_RECTANGLE, 0x20, 0, 168, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0, 0}, - NULL, 0, 0x41CCB4, 0, NULL, NULL, NULL}, + NULL, + 0, + 0x41CCB4, + 0, + NULL, + NULL, + NULL}, // separator when second details is to be displayed {{BAGL_RECTANGLE, 0x31, 30, 216, 260, 1, 1, 0, 0, COLOR_LIGHT_GRAY, COLOR_BG_1, 0, 0}, - NULL, 0, 0, 0, NULL, NULL, NULL}, - UI_BLUE_TEXT(0x71, 30, 245, 100, NULL, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0, COLOR_BLACK, COLOR_BG_1), + NULL, + 0, + 0, + 0, + NULL, + NULL, + NULL}, + UI_BLUE_TEXT(0x71, + 30, + 245, + 100, + NULL, + BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, + 0, + COLOR_BLACK, + COLOR_BG_1), // x-18 when ... - UI_BLUE_TEXT(0x11, 130, 245, 160, NULL, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_RIGHT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x21, 284, 245, 6, BAGL_FONT_SYMBOLS_0_MINIRIGHT, BAGL_FONT_SYMBOLS_0, BAGL_FONT_ALIGNMENT_RIGHT, COLOR_GRAY, COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, 217, 320, 48, ui_transaction_blue_2_details, ui_menu_item_out_over, ui_menu_item_out_over), + UI_BLUE_TEXT(0x11, + 130, + 245, + 160, + NULL, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_RIGHT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x21, + 284, + 245, + 6, + BAGL_FONT_SYMBOLS_0_MINIRIGHT, + BAGL_FONT_SYMBOLS_0, + BAGL_FONT_ALIGNMENT_RIGHT, + COLOR_GRAY, + COLOR_BG_1), + UI_BLUE_TOUCHZONE(0, + 217, + 320, + 48, + ui_transaction_blue_2_details, + ui_menu_item_out_over, + ui_menu_item_out_over), {{BAGL_RECTANGLE, 0x21, 0, 217, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0, 0}, - NULL, 0, 0x41CCB4, 0, NULL, NULL, NULL}, + NULL, + 0, + 0x41CCB4, + 0, + NULL, + NULL, + NULL}, // separator when second details is to be displayed {{BAGL_RECTANGLE, 0x32, 30, 265, 260, 1, 1, 0, 0, COLOR_LIGHT_GRAY, COLOR_BG_1, 0, 0}, - NULL, 0, 0, 0, NULL, NULL, NULL}, - UI_BLUE_TEXT(0x72, 30, 294, 100, NULL, BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0, COLOR_BLACK, COLOR_BG_1), + NULL, + 0, + 0, + 0, + NULL, + NULL, + NULL}, + UI_BLUE_TEXT(0x72, + 30, + 294, + 100, + NULL, + BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, + 0, + COLOR_BLACK, + COLOR_BG_1), // x-18 when ... - UI_BLUE_TEXT(0x12, 130, 294, 160, NULL, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, BAGL_FONT_ALIGNMENT_RIGHT, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x22, 284, 294, 6, BAGL_FONT_SYMBOLS_0_MINIRIGHT, BAGL_FONT_SYMBOLS_0, BAGL_FONT_ALIGNMENT_RIGHT, COLOR_GRAY, COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, 266, 320, 48, ui_transaction_blue_3_details, ui_menu_item_out_over, ui_menu_item_out_over), - {{BAGL_RECTANGLE, 0x22, 0, 266, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0, 0}, // WHY OVER ACTIVATE WHE TOUCING OUT OF RECTANGLE ? ASK OTO - NULL, 0, 0x41CCB4, 0, NULL, NULL, NULL}, - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", "CONFIRM", ui_transaction_blue_cancel_callback, ui_transaction_blue_ok_callback) + UI_BLUE_TEXT(0x12, + 130, + 294, + 160, + NULL, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + BAGL_FONT_ALIGNMENT_RIGHT, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x22, + 284, + 294, + 6, + BAGL_FONT_SYMBOLS_0_MINIRIGHT, + BAGL_FONT_SYMBOLS_0, + BAGL_FONT_ALIGNMENT_RIGHT, + COLOR_GRAY, + COLOR_BG_1), + UI_BLUE_TOUCHZONE(0, + 266, + 320, + 48, + ui_transaction_blue_3_details, + ui_menu_item_out_over, + ui_menu_item_out_over), + {{BAGL_RECTANGLE, + 0x22, + 0, + 266, + 5, + 48, + 0, + 0, + BAGL_FILL, + COLOR_BG_1, + COLOR_BG_1, + 0, + 0}, // WHY OVER ACTIVATE WHE TOUCING OUT OF RECTANGLE ? ASK OTO + NULL, + 0, + 0x41CCB4, + 0, + NULL, + NULL, + NULL}, + + UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", + "CONFIRM", + ui_transaction_blue_cancel_callback, + ui_transaction_blue_ok_callback) }; -const bagl_element_t * -ui_transaction_blue_prepro(const bagl_element_t *element) { +const bagl_element_t *ui_transaction_blue_prepro(const bagl_element_t *element) { copy_element_and_map_coin_colors(element); if (element->component.userid == 0) { return &tmp_element; @@ -550,83 +1046,71 @@ ui_transaction_blue_prepro(const bagl_element_t *element) { return 0; } else { switch (element->component.userid & 0xF0) { - // icon - case 0x40: - return &tmp_element; - break; + // icon + case 0x40: + return &tmp_element; + break; - // TITLE - case 0x60: - tmp_element.text = - ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [3]; - return &tmp_element; - break; + // TITLE + case 0x60: + tmp_element.text = ui_transaction_blue_details_name[G_ui_transaction_blue_state][3]; + return &tmp_element; + break; - // SUBLINE - case 0x50: - tmp_element.text = - ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [4]; - return &tmp_element; - break; + // SUBLINE + case 0x50: + tmp_element.text = ui_transaction_blue_details_name[G_ui_transaction_blue_state][4]; + return &tmp_element; + break; - // details label - case 0x70: - if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & - 0xF]) { - return NULL; - } - tmp_element.text = - ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & - 0xF]; - return &tmp_element; - - // detail value - case 0x10: - // won't display - if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & - 0xF]) { - return NULL; - } - // always display the value - tmp_element.text = - ui_transaction_blue_values[(element->component.userid & 0xF)]; - - // x -= 18 when overflow is detected - if (strlen(ui_transaction_blue_values[(element->component.userid & - 0xF)]) * - BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= - 160) { - tmp_element.component.x -= 18; - } - return &tmp_element; - break; + // details label + case 0x70: + if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] + [element->component.userid & 0xF]) { + return NULL; + } + tmp_element.text = + ui_transaction_blue_details_name[G_ui_transaction_blue_state] + [element->component.userid & 0xF]; + return &tmp_element; - // right arrow and left selection rectangle - case 0x20: - if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & - 0xF]) { - return NULL; - } - if (strlen(ui_transaction_blue_values[(element->component.userid & - 0xF)]) * - BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH < - 160) { - return NULL; - } + // detail value + case 0x10: + // won't display + if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] + [element->component.userid & 0xF]) { + return NULL; + } + // always display the value + tmp_element.text = ui_transaction_blue_values[(element->component.userid & 0xF)]; + + // x -= 18 when overflow is detected + if (strlen(ui_transaction_blue_values[(element->component.userid & 0xF)]) * + BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= + 160) { + tmp_element.component.x -= 18; + } + return &tmp_element; + break; - // horizontal delimiter - case 0x30: - return ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & - 0xF] != NULL - ? &tmp_element - : NULL; + // right arrow and left selection rectangle + case 0x20: + if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] + [element->component.userid & 0xF]) { + return NULL; + } + if (strlen(ui_transaction_blue_values[(element->component.userid & 0xF)]) * + BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH < + 160) { + return NULL; + } + + // horizontal delimiter + case 0x30: + return ui_transaction_blue_details_name[G_ui_transaction_blue_state] + [element->component.userid & 0xF] != NULL + ? &tmp_element + : NULL; } } return &tmp_element; @@ -640,66 +1124,276 @@ const bagl_element_t ui_display_derivation_warning[] = { UI_BLUE_BACKGROUND("WARNING"), UI_BLUE_ICON(0x40, 135, 95, 50, 50, &C_blue_badge_warning, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 185, 320, "The derivation path is unusual.", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 203, 320, "Reject if you're not sure.", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 220, 320, "Contact Ledger support for help.", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 271, 320, "Derivation path:", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 297, 320, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 314, 320, vars.tmp_warning.derivation_path+30, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 331, 320, vars.tmp_warning.derivation_path+60, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 348, 320, vars.tmp_warning.derivation_path+90, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", "CONFIRM", io_seproxyhal_touch_display_cancel, io_seproxyhal_touch_display_address_blue) -}; + UI_BLUE_TEXT(0, + 0, + 185, + 320, + "The derivation path is unusual.", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 203, + 320, + "Reject if you're not sure.", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 220, + 320, + "Contact Ledger support for help.", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 271, + 320, + "Derivation path:", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 297, + 320, + vars.tmp_warning.derivation_path, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 314, + 320, + vars.tmp_warning.derivation_path + 30, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 331, + 320, + vars.tmp_warning.derivation_path + 60, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 348, + 320, + vars.tmp_warning.derivation_path + 90, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + + UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", + "CONFIRM", + io_seproxyhal_touch_display_cancel, + io_seproxyhal_touch_display_address_blue)}; const bagl_element_t ui_display_address_blue[] = { UI_BLUE_BACKGROUND("CONFIRM ACCOUNT"), - UI_BLUE_TEXT(0, 30, 106, 320, "ACCOUNT", BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, 0, COLOR_GRAY, COLOR_BG_1), - - UI_BLUE_TEXT(0x10, 30, 126, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x11, 30, 139, 260, vars.tmp.addressSummary, BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, 0, COLOR_BLACK, COLOR_BG_1), - - {{BAGL_RECTANGLE, 0x02, 320 / 2 - 0x1D * 8 / 2, 150, 8, 8, 0, 0, BAGL_FILL,COLOR_WHITE, COLOR_BLACK, 0, 0}, NULL, 0, 0, 0, NULL, NULL, NULL}, - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", "CONFIRM", io_seproxyhal_touch_display_cancel, io_seproxyhal_touch_display_ok) -}; - + UI_BLUE_TEXT(0, + 30, + 106, + 320, + "ACCOUNT", + BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, + 0, + COLOR_GRAY, + COLOR_BG_1), + + UI_BLUE_TEXT(0x10, + 30, + 126, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + 0, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x11, + 30, + 139, + 260, + vars.tmp.addressSummary, + BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, + 0, + COLOR_BLACK, + COLOR_BG_1), + + {{BAGL_RECTANGLE, + 0x02, + 320 / 2 - 0x1D * 8 / 2, + 150, + 8, + 8, + 0, + 0, + BAGL_FILL, + COLOR_WHITE, + COLOR_BLACK, + 0, + 0}, + NULL, + 0, + 0, + 0, + NULL, + NULL, + NULL}, + + UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", + "CONFIRM", + io_seproxyhal_touch_display_cancel, + io_seproxyhal_touch_display_ok)}; const bagl_element_t ui_display_token_blue[] = { UI_BLUE_BACKGROUND("PUBLIC KEY EXPORT"), - UI_BLUE_TEXT(0, 30, 185, 260, "Check if the following token is", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 30, 201, 260, "identical on both devices:", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0x10, 30, 240, 260, G_io_apdu_buffer+200, BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", "CONFIRM", io_seproxyhal_touch_display_token_cancel, io_seproxyhal_touch_display_token_ok) -}; + UI_BLUE_TEXT(0, + 30, + 185, + 260, + "Check if the following token is", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 30, + 201, + 260, + "identical on both devices:", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0x10, + 30, + 240, + 260, + G_io_apdu_buffer + 200, + BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + + UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", + "CONFIRM", + io_seproxyhal_touch_display_token_cancel, + io_seproxyhal_touch_display_token_ok)}; const bagl_element_t ui_request_pubkey_approval_blue[] = { UI_BLUE_BACKGROUND("PUBLIC KEY EXPORT"), - UI_BLUE_TEXT(0, 0, 160, 320, "Approve to export your public keys", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", "CONFIRM", io_seproxyhal_touch_display_cancel, io_seproxyhal_touch_display_ok) -}; + UI_BLUE_TEXT(0, + 0, + 160, + 320, + "Approve to export your public keys", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + + UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", + "CONFIRM", + io_seproxyhal_touch_display_cancel, + io_seproxyhal_touch_display_ok)}; const bagl_element_t ui_request_change_path_approval_blue[] = { UI_BLUE_BACKGROUND("WARNING"), UI_BLUE_ICON(0x40, 135, 95, 50, 50, &C_blue_badge_warning, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 185, 320, "The change path is unusual.", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 203, 320, "Reject if you're not sure.", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 220, 320, "Contact Ledger support for help.", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 271, 320, "Change path:", BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 297, 320, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 314, 320, vars.tmp_warning.derivation_path+30, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 331, 320, vars.tmp_warning.derivation_path+60, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - UI_BLUE_TEXT(0, 0, 348, 320, vars.tmp_warning.derivation_path+90, BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, BAGL_FONT_ALIGNMENT_CENTER, COLOR_BLACK, COLOR_BG_1), - - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", "CONFIRM", io_seproxyhal_touch_display_cancel, io_seproxyhal_touch_display_ok) -}; + UI_BLUE_TEXT(0, + 0, + 185, + 320, + "The change path is unusual.", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 203, + 320, + "Reject if you're not sure.", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 220, + 320, + "Contact Ledger support for help.", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 271, + 320, + "Change path:", + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 297, + 320, + vars.tmp_warning.derivation_path, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 314, + 320, + vars.tmp_warning.derivation_path + 30, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 331, + 320, + vars.tmp_warning.derivation_path + 60, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + UI_BLUE_TEXT(0, + 0, + 348, + 320, + vars.tmp_warning.derivation_path + 90, + BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, + BAGL_FONT_ALIGNMENT_CENTER, + COLOR_BLACK, + COLOR_BG_1), + + UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", + "CONFIRM", + io_seproxyhal_touch_display_cancel, + io_seproxyhal_touch_display_ok)}; unsigned int ui_display_address_blue_prepro(const bagl_element_t *element) { bagl_icon_details_t *icon_details = &vars.tmpqr.icon_details; @@ -708,71 +1402,65 @@ unsigned int ui_display_address_blue_prepro(const bagl_element_t *element) { if (element->component.userid > 0) { unsigned int length = strlen(G_io_apdu_buffer + 200); switch (element->component.userid) { - // qrcode, need magnifying - case 0x02: { - unsigned int x, y, x_off, y_off, bit; + // qrcode, need magnifying + case 0x02: { + unsigned int x, y, x_off, y_off, bit; #define PIXEL_SIZE 5 - os_memmove(&tmp_element, element, sizeof(bagl_element_t)); - tmp_element.component.width = PIXEL_SIZE; - tmp_element.component.height = PIXEL_SIZE; - x_off = 320 / 2 - vars.tmpqr.qrcode[0] * PIXEL_SIZE / 2; - y_off = - 139 + (414 - 139) / 2 - vars.tmpqr.qrcode[0] * PIXEL_SIZE / 2; - bit = 0; - - y = 0; - x = 0; - tmp_element.component.fgcolor = - vars.tmpqr.qrcode[1 + (bit >> 3)] & (1 << (bit & 0x7)) - ? COLOR_BLACK - : COLOR_WHITE; - tmp_element.component.x = x_off + x * PIXEL_SIZE; - tmp_element.component.y = y_off + y * PIXEL_SIZE; - bit++; - x = 1; - goto send_and_next; - - for (y = 0; y < vars.tmpqr.qrcode[0]; y++) { - for (x = 0; x < vars.tmpqr.qrcode[0]; x++) { - send_and_next: - io_seproxyhal_display(&tmp_element); - // tmp_element.component.fgcolor = - // vars.tmpqr.qrcode[1+((y*0x1D+x)>>3)]&(1<<((y*0x1D+x)&0x7)) - // ? COLOR_BLACK: COLOR_WHITE; - tmp_element.component.fgcolor = - vars.tmpqr.qrcode[1 + (bit >> 3)] & (1 << (bit & 0x7)) - ? COLOR_BLACK - : COLOR_WHITE; - tmp_element.component.x = x_off + x * PIXEL_SIZE; - tmp_element.component.y = y_off + y * PIXEL_SIZE; - bit++; - io_seproxyhal_spi_recv(G_io_seproxyhal_spi_buffer, - sizeof(G_io_seproxyhal_spi_buffer), - 0); + os_memmove(&tmp_element, element, sizeof(bagl_element_t)); + tmp_element.component.width = PIXEL_SIZE; + tmp_element.component.height = PIXEL_SIZE; + x_off = 320 / 2 - vars.tmpqr.qrcode[0] * PIXEL_SIZE / 2; + y_off = 139 + (414 - 139) / 2 - vars.tmpqr.qrcode[0] * PIXEL_SIZE / 2; + bit = 0; + + y = 0; + x = 0; + tmp_element.component.fgcolor = + vars.tmpqr.qrcode[1 + (bit >> 3)] & (1 << (bit & 0x7)) ? COLOR_BLACK + : COLOR_WHITE; + tmp_element.component.x = x_off + x * PIXEL_SIZE; + tmp_element.component.y = y_off + y * PIXEL_SIZE; + bit++; + x = 1; + goto send_and_next; + + for (y = 0; y < vars.tmpqr.qrcode[0]; y++) { + for (x = 0; x < vars.tmpqr.qrcode[0]; x++) { + send_and_next: + io_seproxyhal_display(&tmp_element); + // tmp_element.component.fgcolor = + // vars.tmpqr.qrcode[1+((y*0x1D+x)>>3)]&(1<<((y*0x1D+x)&0x7)) + // ? COLOR_BLACK: COLOR_WHITE; + tmp_element.component.fgcolor = + vars.tmpqr.qrcode[1 + (bit >> 3)] & (1 << (bit & 0x7)) ? COLOR_BLACK + : COLOR_WHITE; + tmp_element.component.x = x_off + x * PIXEL_SIZE; + tmp_element.component.y = y_off + y * PIXEL_SIZE; + bit++; + io_seproxyhal_spi_recv(G_io_seproxyhal_spi_buffer, + sizeof(G_io_seproxyhal_spi_buffer), + 0); + } } + // don't use the common draw method, we've already drawn the + // component + return 0; } - // don't use the common draw method, we've already drawn the - // component - return 0; - } - // address lines - case 0x10: - case 0x11: - default: - if (length >= - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE) { - os_memset(vars.tmpqr.addressSummary, 0, MAX_CHAR_PER_LINE + 1); - os_memmove(vars.tmpqr.addressSummary, - G_io_apdu_buffer + 200 + - (element->component.userid & 0xF) * - MAX_CHAR_PER_LINE, - MIN(length - (element->component.userid & 0xF) * - MAX_CHAR_PER_LINE, - MAX_CHAR_PER_LINE)); - return &tmp_element; - } - break; + // address lines + case 0x10: + case 0x11: + default: + if (length >= (element->component.userid & 0xF) * MAX_CHAR_PER_LINE) { + os_memset(vars.tmpqr.addressSummary, 0, MAX_CHAR_PER_LINE + 1); + os_memmove(vars.tmpqr.addressSummary, + G_io_apdu_buffer + 200 + + (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, + MIN(length - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, + MAX_CHAR_PER_LINE)); + return &tmp_element; + } + break; } // nothing to draw for this line return 0; @@ -796,7 +1484,7 @@ unsigned int ui_request_change_path_approval_blue_prepro(const bagl_element_t *e } unsigned int ui_display_derivation_warning_button(unsigned int button_mask, - unsigned int button_mask_counter) { + unsigned int button_mask_counter) { return 0; } @@ -806,23 +1494,20 @@ unsigned int ui_display_address_blue_button(unsigned int button_mask, } unsigned int ui_display_token_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ + unsigned int button_mask_counter) { return 0; } unsigned int ui_request_pubkey_approval_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ + unsigned int button_mask_counter) { return 0; } unsigned int ui_request_change_path_approval_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ + unsigned int button_mask_counter) { return 0; } -#endif // #if defined(TARGET_BLUE) +#endif // #if defined(TARGET_BLUE) #if defined(TARGET_NANOS) @@ -838,7 +1523,12 @@ const bagl_element_t ui_display_address_nanos[] = { UI_NANOS_TEXT(2, 0, 26, 128, "path is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Derivation path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(0x83, + 15, + 26, + 98, + vars.tmp_warning.derivation_path, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), @@ -854,8 +1544,12 @@ const bagl_element_t ui_display_address_nanos[] = { UI_NANOS_TEXT(6, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), // Hax, avoid wasting space - UI_NANOS_SCROLLING_TEXT(0x86, 15, 26, 98, G_io_apdu_buffer + 199, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_SCROLLING_TEXT(0x86, + 15, + 26, + 98, + G_io_apdu_buffer + 199, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; const bagl_element_t ui_display_token_nanos[] = { @@ -864,16 +1558,14 @@ const bagl_element_t ui_display_token_nanos[] = { UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), UI_NANOS_TEXT(1, 0, 12, 128, "Confirm token", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, G_io_apdu_buffer + 200, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_TEXT(1, 0, 26, 128, G_io_apdu_buffer + 200, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; const bagl_element_t ui_request_pubkey_approval_nanos[] = { UI_NANOS_BACKGROUND(), UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), UI_NANOS_TEXT(1, 0, 12, 128, "Export", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, "public key?", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_TEXT(1, 0, 26, 128, "public key?", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; const bagl_element_t ui_request_change_path_approval_nanos[] = { UI_NANOS_BACKGROUND(), @@ -884,36 +1576,41 @@ const bagl_element_t ui_request_change_path_approval_nanos[] = { UI_NANOS_TEXT(2, 0, 26, 128, "is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Change path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(0x83, + 15, + 26, + 98, + vars.tmp_warning.derivation_path, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; unsigned int ui_display_address_nanos_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); if (display) { switch (element->component.userid) { - case 0x83: - ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - case 5: - UX_CALLBACK_SET_INTERVAL(2000); - ux_loop_over_curr_element = 0; // allow next timer to increment ux_step when triggered - break; - case 0x86: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - // ugly ux tricks, loops around last 2 screens - ux_step -= 1; // loops back to previous element on next redraw - ux_loop_over_curr_element = 1; // when the timer will trigger, ux_step won't be incremented, only redraw - break; + case 0x83: + ux_loop_over_curr_element = 1; + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; + case 5: + UX_CALLBACK_SET_INTERVAL(2000); + ux_loop_over_curr_element = + 0; // allow next timer to increment ux_step when triggered + break; + case 0x86: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + // ugly ux tricks, loops around last 2 screens + ux_step -= 1; // loops back to previous element on next redraw + ux_loop_over_curr_element = 1; // when the timer will trigger, ux_step won't be + // incremented, only redraw + break; } } return display; @@ -927,8 +1624,8 @@ unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t * if (display) { if (element->component.userid & 0x80) { ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); } } return display; @@ -939,11 +1636,11 @@ unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t * unsigned int ui_display_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + unsigned int button_mask_counter); unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + unsigned int button_mask_counter); unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + unsigned int button_mask_counter); const bagl_element_t ui_verify_nanos[] = { UI_NANOS_BACKGROUND(), @@ -956,14 +1653,18 @@ const bagl_element_t ui_verify_nanos[] = { UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(3, + 23, + 26, + 82, + vars.tmp.fullAddress, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(4, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_REGULAR_11px), UI_NANOS_SCROLLING_TEXT(4, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) }; -unsigned int ui_verify_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); +unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); const bagl_element_t ui_verify_output_nanos[] = { @@ -977,8 +1678,12 @@ const bagl_element_t ui_verify_output_nanos[] = { UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_SCROLLING_TEXT(3, + 23, + 26, + 82, + vars.tmp.fullAddress, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; unsigned int ui_verify_output_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); @@ -993,7 +1698,6 @@ const bagl_element_t ui_finalize_nanos[] = { UI_NANOS_TEXT(2, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) - /* TODO {{BAGL_LABELINE , 0x02, 0, 12, 128, 12, 0, 0, 0 , COLOR_WHITE, COLOR_BLACK, @@ -1005,8 +1709,7 @@ const bagl_element_t ui_finalize_nanos[] = { vars.tmp.fullAmount, 0, 0, 0, NULL, NULL, NULL }, */ }; -unsigned int ui_finalize_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); +unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); // display or not according to step, and adjust delay unsigned int ui_verify_prepro(const bagl_element_t *element) { @@ -1014,15 +1717,15 @@ unsigned int ui_verify_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - case 4: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + case 4: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -1035,14 +1738,14 @@ unsigned int ui_verify_output_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -1055,13 +1758,13 @@ unsigned int ui_finalize_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -1077,24 +1780,27 @@ const bagl_element_t ui_verify_message_signature_nanos[] = { UI_NANOS_TEXT(1, 0, 26, 128, "message", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(2, 0, 12, 128, "Message hash", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; -unsigned int -ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + UI_NANOS_SCROLLING_TEXT(2, + 23, + 26, + 82, + vars.tmp.fullAddress, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; +unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); unsigned int ui_verify_message_prepro(const bagl_element_t *element) { if (element->component.userid > 0) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -1102,20 +1808,19 @@ unsigned int ui_verify_message_prepro(const bagl_element_t *element) { return 1; } -#endif // #if defined(TARGET_NANOS) - +#endif // #if defined(TARGET_NANOS) #ifdef TARGET_BLUE unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e) { - UX_DISPLAY(ui_settings_blue, ui_settings_blue_prepro); - return 0; // do not redraw button, screen has switched + UX_DISPLAY(ui_settings_blue, ui_settings_blue_prepro); + return 0; // do not redraw button, screen has switched } unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e) { // go back to the home screen os_sched_exit(0); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_address_blue(const bagl_element_t *e) { @@ -1123,7 +1828,7 @@ unsigned int io_seproxyhal_touch_display_address_blue(const bagl_element_t *e) { UX_DISPLAY(ui_display_address_blue, ui_display_address_blue_prepro); return 0; } -#endif // TARGET_BLUE +#endif // TARGET_BLUE unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { // user denied the transaction, tell the USB side @@ -1131,7 +1836,7 @@ unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { // redraw ui ui_idle(); } - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { @@ -1140,25 +1845,23 @@ unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { // redraw ui ui_idle(); } - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int -io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { // user denied the transaction, tell the USB side btchip_bagl_user_action_message_signing(0); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int -io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { // user accepted the transaction, tell the USB side btchip_bagl_user_action_message_signing(1); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { @@ -1166,7 +1869,7 @@ unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { btchip_bagl_user_action_display(0); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { @@ -1174,7 +1877,7 @@ unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { btchip_bagl_user_action_display(1); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e) { @@ -1184,30 +1887,29 @@ unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e) { btchip_bagl_user_action_display(0); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } - unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e) { +unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e) { // Set the valid token flag btchip_context_D.has_valid_token = true; // user approved the token, tell the USB side btchip_bagl_user_action_display(1); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } #if defined(TARGET_NANOS) -unsigned int ui_verify_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } @@ -1215,157 +1917,138 @@ unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int ui_verify_output_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } -unsigned int ui_finalize_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } -unsigned int -ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_message_signature_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_message_signature_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_message_signature_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_message_signature_verify_ok(NULL); + break; } return 0; } unsigned int ui_display_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { - if (ux_step == 3) - { - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - break; - } - } - else if (ux_step >= 4) - { - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } - else - { - if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) - { - // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) - if(ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } + if (ux_step == 3) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: // prepare next screen ux_step = (ux_step + 1) % ux_step_count; // redisplay screen UX_REDISPLAY(); + break; + } + } else if (ux_step >= 4) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; + } + } else { + if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { + // if we were looping over a single element, disable this loop and diffuse the redisplay + // timeout (used by scrolling text) + if (ux_loop_over_curr_element) { + ux_loop_over_curr_element = 0; + ux.callback_interval_ms = 0; + } + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); } } return 0; } unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_token_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_token_ok(NULL); - break; + unsigned int button_mask_counter) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_token_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_token_ok(NULL); + break; } return 0; } unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - return 0; -} - - - unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ - if (ux_step == 3) - { - switch (button_mask) - { + unsigned int button_mask_counter) { + switch (button_mask) { case BUTTON_EVT_RELEASED | BUTTON_LEFT: io_seproxyhal_touch_display_cancel(NULL); break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; } - else - { - if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) - { - // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) - if(ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); + return 0; +} + +unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { + if (ux_step == 3) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; + } + } else { + if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { + // if we were looping over a single element, disable this loop and diffuse the redisplay + // timeout (used by scrolling text) + if (ux_loop_over_curr_element) { + ux_loop_over_curr_element = 0; + ux.callback_interval_ms = 0; + } + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); } } return 0; } -#endif // #if defined(TARGET_NANOS) +#endif // #if defined(TARGET_NANOS) #if defined(TARGET_BLUE) void ui_transaction_blue_init(void) { @@ -1373,10 +2056,8 @@ void ui_transaction_blue_init(void) { } void ui_transaction_full_blue_init(void) { - ui_transaction_blue_ok = - (bagl_element_callback_t)io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = - (bagl_element_callback_t)io_seproxyhal_touch_verify_cancel; + ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; + ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; G_ui_transaction_blue_state = TRANSACTION_FULL; ui_transaction_blue_values[0] = vars.tmp.fullAmount; ui_transaction_blue_values[1] = vars.tmp.fullAddress; @@ -1385,15 +2066,14 @@ void ui_transaction_full_blue_init(void) { } void ui_transaction_output_blue_init(void) { - ui_transaction_blue_ok = - (bagl_element_callback_t)io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = - (bagl_element_callback_t)io_seproxyhal_touch_verify_cancel; + ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; + ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; G_ui_transaction_blue_state = TRANSACTION_OUTPUT; - snprintf( - vars.tmp.output_numbering, sizeof(vars.tmp.output_numbering), "%d / %d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1, - btchip_context_D.totalOutputs); + snprintf(vars.tmp.output_numbering, + sizeof(vars.tmp.output_numbering), + "%d / %d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1, + btchip_context_D.totalOutputs); ui_transaction_blue_values[0] = vars.tmp.output_numbering; ui_transaction_blue_values[1] = vars.tmp.fullAddress; ui_transaction_blue_values[2] = vars.tmp.fullAmount; @@ -1401,10 +2081,8 @@ void ui_transaction_output_blue_init(void) { } void ui_transaction_finalize_blue_init(void) { - ui_transaction_blue_ok = - (bagl_element_callback_t)io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = - (bagl_element_callback_t)io_seproxyhal_touch_verify_cancel; + ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; + ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; G_ui_transaction_blue_state = TRANSACTION_FINALIZE; ui_transaction_blue_values[0] = vars.tmp.fullAmount; ui_transaction_blue_values[1] = vars.tmp.feesAmount; @@ -1413,10 +2091,10 @@ void ui_transaction_finalize_blue_init(void) { } void ui_message_signature_blue_init(void) { - ui_transaction_blue_ok = (bagl_element_callback_t) - io_seproxyhal_touch_message_signature_verify_ok; - ui_transaction_blue_cancel = (bagl_element_callback_t) - io_seproxyhal_touch_message_signature_verify_cancel; + ui_transaction_blue_ok = + (bagl_element_callback_t) io_seproxyhal_touch_message_signature_verify_ok; + ui_transaction_blue_cancel = + (bagl_element_callback_t) io_seproxyhal_touch_message_signature_verify_cancel; G_ui_transaction_blue_state = TRANSACTION_MESSAGE; ui_transaction_blue_values[0] = vars.tmp.fullAddress; ui_transaction_blue_values[1] = NULL; @@ -1425,484 +2103,411 @@ void ui_message_signature_blue_init(void) { } void ui_transaction_p2sh_blue_init(void) { - ui_transaction_blue_ok = - (bagl_element_callback_t)io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = - (bagl_element_callback_t)io_seproxyhal_touch_verify_cancel; + ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; + ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; G_ui_transaction_blue_state = TRANSACTION_P2SH; ui_transaction_blue_values[0] = NULL; ui_transaction_blue_values[1] = NULL; ui_transaction_blue_values[2] = NULL; ui_transaction_blue_init(); } -#endif // #if defined(TARGET_BLUE) - +#endif // #if defined(TARGET_BLUE) #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) -const char* settings_submenu_getter(unsigned int idx); +const char *settings_submenu_getter(unsigned int idx); void settings_submenu_selector(unsigned int idx); - void settings_pubkey_export_change(unsigned int enabled) { - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); + nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &enabled, 1); ui_idle(); } ////////////////////////////////////////////////////////////////////////////////////// // Public keys export submenu: -const char* const settings_pubkey_export_getter_values[] = { - "Auto Approval", - "Manual Approval", - "Back" -}; +const char *const settings_pubkey_export_getter_values[] = {"Auto Approval", + "Manual Approval", + "Back"}; -const char* settings_pubkey_export_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { - return settings_pubkey_export_getter_values[idx]; - } - return NULL; +const char *settings_pubkey_export_getter(unsigned int idx) { + if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { + return settings_pubkey_export_getter_values[idx]; + } + return NULL; } void settings_pubkey_export_selector(unsigned int idx) { - switch(idx) { - case 0: - settings_pubkey_export_change(0); - break; - case 1: - settings_pubkey_export_change(1); - break; - default: - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); - } + switch (idx) { + case 0: + settings_pubkey_export_change(0); + break; + case 1: + settings_pubkey_export_change(1); + break; + default: + ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); + } } ////////////////////////////////////////////////////////////////////////////////////// // Settings menu: -const char* const settings_submenu_getter_values[] = { - "Public keys export", - "Back", +const char *const settings_submenu_getter_values[] = { + "Public keys export", + "Back", }; -const char* settings_submenu_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_submenu_getter_values)) { - return settings_submenu_getter_values[idx]; - } - return NULL; +const char *settings_submenu_getter(unsigned int idx) { + if (idx < ARRAYLEN(settings_submenu_getter_values)) { + return settings_submenu_getter_values[idx]; + } + return NULL; } void settings_submenu_selector(unsigned int idx) { - switch(idx) { - case 0: - ux_menulist_init_select(0, settings_pubkey_export_getter, settings_pubkey_export_selector, N_btchip.pubKeyRequestRestriction); - break; - default: - ui_idle(); - } + switch (idx) { + case 0: + ux_menulist_init_select(0, + settings_pubkey_export_getter, + settings_pubkey_export_selector, + N_btchip.pubKeyRequestRestriction); + break; + default: + ui_idle(); + } } ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_idle_flow_1_step, - nn, - { - "Application", - "is ready", - }); -UX_STEP_VALID( - ux_idle_flow_2_step, - pb, - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector), - { - &C_icon_coggle, - "Settings", - }); -UX_STEP_NOCB( - ux_idle_flow_3_step, - bn, - { - "Version", - APPVERSION, - }); -UX_STEP_VALID( - ux_idle_flow_4_step, - pb, - os_sched_exit(-1), - { - &C_icon_dashboard_x, - "Quit", - }); +UX_STEP_NOCB(ux_idle_flow_1_step, + nn, + { + "Application", + "is ready", + }); +UX_STEP_VALID(ux_idle_flow_2_step, + pb, + ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector), + { + &C_icon_coggle, + "Settings", + }); +UX_STEP_NOCB(ux_idle_flow_3_step, + bn, + { + "Version", + APPVERSION, + }); +UX_STEP_VALID(ux_idle_flow_4_step, + pb, + os_sched_exit(-1), + { + &C_icon_dashboard_x, + "Quit", + }); UX_FLOW(ux_idle_flow, - &ux_idle_flow_1_step, - &ux_idle_flow_2_step, - &ux_idle_flow_3_step, - &ux_idle_flow_4_step -); + &ux_idle_flow_1_step, + &ux_idle_flow_2_step, + &ux_idle_flow_3_step, + &ux_idle_flow_4_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_sign_flow_1_step, - pnn, - { - &C_icon_certificate, - "Sign", - "message", - }); -UX_STEP_NOCB( - ux_sign_flow_2_step, - bnnn_paging, - { - .title = "Message hash", - .text = vars.tmp.fullAddress, - }); -UX_STEP_VALID( - ux_sign_flow_3_step, - pbb, - io_seproxyhal_touch_message_signature_verify_ok(NULL), - { - &C_icon_validate_14, - "Sign", - "message", - }); -UX_STEP_VALID( - ux_sign_flow_4_step, - pbb, - io_seproxyhal_touch_message_signature_verify_cancel(NULL), - { - &C_icon_crossmark, - "Cancel", - "signature", - }); +UX_STEP_NOCB(ux_sign_flow_1_step, + pnn, + { + &C_icon_certificate, + "Sign", + "message", + }); +UX_STEP_NOCB(ux_sign_flow_2_step, + bnnn_paging, + { + .title = "Message hash", + .text = vars.tmp.fullAddress, + }); +UX_STEP_VALID(ux_sign_flow_3_step, + pbb, + io_seproxyhal_touch_message_signature_verify_ok(NULL), + { + &C_icon_validate_14, + "Sign", + "message", + }); +UX_STEP_VALID(ux_sign_flow_4_step, + pbb, + io_seproxyhal_touch_message_signature_verify_cancel(NULL), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); UX_FLOW(ux_sign_flow, - &ux_sign_flow_1_step, - &ux_sign_flow_2_step, - &ux_sign_flow_3_step, - &ux_sign_flow_4_step -); + &ux_sign_flow_1_step, + &ux_sign_flow_2_step, + &ux_sign_flow_3_step, + &ux_sign_flow_4_step); ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_confirm_full_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction", - }); -UX_STEP_NOCB( - ux_confirm_full_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount - }); -UX_STEP_NOCB( - ux_confirm_full_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB( - ux_confirm_full_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_confirm_full_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send", - }); -UX_STEP_VALID( - ux_confirm_full_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); + pnn, + { + &C_icon_eye, + "Review", + "transaction", + }); +UX_STEP_NOCB(ux_confirm_full_flow_2_step, + bnnn_paging, + {.title = "Amount", .text = vars.tmp.fullAmount}); +UX_STEP_NOCB(ux_confirm_full_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB(ux_confirm_full_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID(ux_confirm_full_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + "and send", + }); +UX_STEP_VALID(ux_confirm_full_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress / Fees: feesAmount UX_FLOW(ux_confirm_full_flow, - &ux_confirm_full_flow_1_step, - &ux_confirm_full_flow_2_step, - &ux_confirm_full_flow_3_step, - &ux_confirm_full_flow_4_step, - &ux_confirm_full_flow_5_step, - &ux_confirm_full_flow_6_step -); + &ux_confirm_full_flow_1_step, + &ux_confirm_full_flow_2_step, + &ux_confirm_full_flow_3_step, + &ux_confirm_full_flow_4_step, + &ux_confirm_full_flow_5_step, + &ux_confirm_full_flow_6_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_confirm_single_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction" - }); -UX_STEP_NOCB( - ux_confirm_single_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount, - }); -UX_STEP_NOCB( - ux_confirm_single_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB( - ux_confirm_single_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_confirm_single_flow_5_step, - pb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - }); -UX_STEP_VALID( - ux_confirm_single_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, {&C_icon_eye, "Review", "transaction"}); +UX_STEP_NOCB(ux_confirm_single_flow_2_step, + bnnn_paging, + { + .title = "Amount", + .text = vars.tmp.fullAmount, + }); +UX_STEP_NOCB(ux_confirm_single_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB(ux_confirm_single_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID(ux_confirm_single_flow_5_step, + pb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + }); +UX_STEP_VALID(ux_confirm_single_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: fullAddress UX_FLOW(ux_confirm_single_flow, - &ux_confirm_single_flow_1_step, - &ux_confirm_single_flow_2_step, - &ux_confirm_single_flow_3_step, - &ux_confirm_single_flow_4_step, - &ux_confirm_single_flow_5_step, - &ux_confirm_single_flow_6_step -); + &ux_confirm_single_flow_1_step, + &ux_confirm_single_flow_2_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_4_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_finalize_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction" - }); -UX_STEP_NOCB( - ux_finalize_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_finalize_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send" - }); -UX_STEP_VALID( - ux_finalize_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB(ux_finalize_flow_1_step, pnn, {&C_icon_eye, "Review", "transaction"}); +UX_STEP_NOCB(ux_finalize_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID(ux_finalize_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + {&C_icon_validate_14, "Accept", "and send"}); +UX_STEP_VALID(ux_finalize_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // finalize: confirm transaction / Fees: feesAmount UX_FLOW(ux_finalize_flow, - &ux_finalize_flow_1_step, - &ux_finalize_flow_4_step, - &ux_finalize_flow_5_step, - &ux_finalize_flow_6_step -); + &ux_finalize_flow_1_step, + &ux_finalize_flow_4_step, + &ux_finalize_flow_5_step, + &ux_finalize_flow_6_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_display_public_flow_1_step, - pnn, - { - &C_icon_warning, - "The derivation", - "path is unusual!", - }); -UX_STEP_NOCB( - ux_display_public_flow_2_step, - bnnn_paging, - { - .title = "Derivation path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_VALID( - ux_display_public_flow_3_step, - pnn, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_NOCB( - ux_display_public_flow_4_step, - pnn, - { - &C_icon_validate_14, - "Approve derivation", - "path", - }); -UX_STEP_NOCB( - ux_display_public_flow_5_step, - bnnn_paging, - { - .title = "Address", - .text = G_io_apdu_buffer+200, - }); -UX_STEP_VALID( - ux_display_public_flow_6_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); -UX_STEP_VALID( - ux_display_public_flow_7_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB(ux_display_public_flow_1_step, + pnn, + { + &C_icon_warning, + "The derivation", + "path is unusual!", + }); +UX_STEP_NOCB(ux_display_public_flow_2_step, + bnnn_paging, + { + .title = "Derivation path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_VALID(ux_display_public_flow_3_step, + pnn, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_NOCB(ux_display_public_flow_4_step, + pnn, + { + &C_icon_validate_14, + "Approve derivation", + "path", + }); +UX_STEP_NOCB(ux_display_public_flow_5_step, + bnnn_paging, + { + .title = "Address", + .text = G_io_apdu_buffer + 200, + }); +UX_STEP_VALID(ux_display_public_flow_6_step, + pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); +UX_STEP_VALID(ux_display_public_flow_7_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); UX_FLOW(ux_display_public_with_warning_flow, - &ux_display_public_flow_1_step, - &ux_display_public_flow_2_step, - &ux_display_public_flow_3_step, - &ux_display_public_flow_4_step, - FLOW_BARRIER, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step -); + &ux_display_public_flow_1_step, + &ux_display_public_flow_2_step, + &ux_display_public_flow_3_step, + &ux_display_public_flow_4_step, + FLOW_BARRIER, + &ux_display_public_flow_5_step, + &ux_display_public_flow_6_step, + &ux_display_public_flow_7_step); UX_FLOW(ux_display_public_flow, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step -); - + &ux_display_public_flow_5_step, + &ux_display_public_flow_6_step, + &ux_display_public_flow_7_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_VALID( - ux_display_token_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Confirm token", - G_io_apdu_buffer+200, - }); -UX_STEP_VALID( - ux_display_token_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_token_flow, - &ux_display_token_flow_1_step, - &ux_display_token_flow_2_step -); +UX_STEP_VALID(ux_display_token_flow_1_step, + pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Confirm token", + G_io_apdu_buffer + 200, + }); +UX_STEP_VALID(ux_display_token_flow_2_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_display_token_flow, &ux_display_token_flow_1_step, &ux_display_token_flow_2_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_VALID( - ux_request_pubkey_approval_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Export", - "public key?", - }); -UX_STEP_VALID( - ux_request_pubkey_approval_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_VALID(ux_request_pubkey_approval_flow_1_step, + pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Export", + "public key?", + }); +UX_STEP_VALID(ux_request_pubkey_approval_flow_2_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); UX_FLOW(ux_request_pubkey_approval_flow, - &ux_request_pubkey_approval_flow_1_step, - &ux_request_pubkey_approval_flow_2_step -); + &ux_request_pubkey_approval_flow_1_step, + &ux_request_pubkey_approval_flow_2_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_request_change_path_approval_flow_1_step, - pbb, - { - &C_icon_eye, - "The change path", - "is unusual", - }); -UX_STEP_NOCB( - ux_request_change_path_approval_flow_2_step, - bnnn_paging, - { - .title = "Change path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_VALID( - ux_request_change_path_approval_flow_3_step, - pbb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_VALID( - ux_request_change_path_approval_flow_4_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); +UX_STEP_NOCB(ux_request_change_path_approval_flow_1_step, + pbb, + { + &C_icon_eye, + "The change path", + "is unusual", + }); +UX_STEP_NOCB(ux_request_change_path_approval_flow_2_step, + bnnn_paging, + { + .title = "Change path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_VALID(ux_request_change_path_approval_flow_3_step, + pbb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_VALID(ux_request_change_path_approval_flow_4_step, + pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); UX_FLOW(ux_request_change_path_approval_flow, - &ux_request_change_path_approval_flow_1_step, - &ux_request_change_path_approval_flow_2_step, - &ux_request_change_path_approval_flow_3_step, - &ux_request_change_path_approval_flow_4_step -); + &ux_request_change_path_approval_flow_1_step, + &ux_request_change_path_approval_flow_2_step, + &ux_request_change_path_approval_flow_3_step, + &ux_request_change_path_approval_flow_4_step); -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 void ui_idle(void) { ux_step_count = 0; @@ -1914,42 +2519,41 @@ void ui_idle(void) { UX_MENU_DISPLAY(0, menu_main, NULL); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) // reserve a display stack slot if none yet - if(G_ux.stack_count == 0) { + if (G_ux.stack_count == 0) { ux_stack_push(); } ux_flow_init(0, ux_idle_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { - io_seproxyhal_display_default((bagl_element_t *)element); + io_seproxyhal_display_default((bagl_element_t *) element); } } unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; + case CHANNEL_KEYBOARD: + break; - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); + // multiplexed io exchange over a SPI channel and TLV encapsulated protocol + case CHANNEL_SPI: + if (tx_len) { + io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); + if (channel & IO_RESET_AFTER_REPLIED) { + reset(); + } + return 0; // nothing received from the master so far (it's a tx + // transaction) + } else { + return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, - sizeof(G_io_apdu_buffer), 0); - } - default: - THROW(INVALID_PARAMETER); + default: + THROW(INVALID_PARAMETER); } return 0; } @@ -1960,43 +2564,43 @@ unsigned char io_event(unsigned char channel) { // can't have more than one tag in the reply, not supported yet. switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - // no break is intentional - default: - UX_DEFAULT_EVENT(); - break; - - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { - // don't redisplay if UX not allowed (pin locked in the common bolos - // ux ?) - if (ux_step_count && UX_ALLOWED) { - // prepare next screen - if(!ux_loop_over_curr_element) { - ux_step = (ux_step + 1) % ux_step_count; - } - // redisplay screen - UX_REDISPLAY(); + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); + break; + + case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: + UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); + break; + + case SEPROXYHAL_TAG_STATUS_EVENT: + if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && + !(U4BE(G_io_seproxyhal_spi_buffer, 3) & + SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { + THROW(EXCEPTION_IO_RESET); } - }); - break; + // no break is intentional + default: + UX_DEFAULT_EVENT(); + break; + + case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: + UX_DISPLAYED_EVENT({}); + break; + + case SEPROXYHAL_TAG_TICKER_EVENT: + UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { + // don't redisplay if UX not allowed (pin locked in the common bolos + // ux ?) + if (ux_step_count && UX_ALLOWED) { + // prepare next screen + if (!ux_loop_over_curr_element) { + ux_step = (ux_step + 1) % ux_step_count; + } + // redisplay screen + UX_REDISPLAY(); + } + }); + break; } // close the event if not done previously (by a display or whatever) @@ -2015,24 +2619,25 @@ uint8_t prepare_fees() { } else { unsigned char fees[8]; unsigned short textSize; - if (transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.totalOutputAmount)) { + if (transaction_amount_sub_be(fees, + btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.totalOutputAmount)) { PRINTF("Fees: %.*H\n", 8, fees); - PRINTF("transactionAmount:: %.*H\n", 8, btchip_context_D.transactionContext.transactionAmount); + PRINTF("transactionAmount:: %.*H\n", + 8, + btchip_context_D.transactionContext.transactionAmount); PRINTF("totalOutputAmount: %.*H\n", 8, btchip_context_D.totalOutputAmount); PRINTF("Error : Fees not consistent"); goto error; } - os_memmove(vars.tmp.feesAmount, btchip_context_D.shortCoinId, + os_memmove(vars.tmp.feesAmount, + btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - btchip_context_D.shortCoinIdLength + 1); + (unsigned char *) (vars.tmp.feesAmount + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; } return 1; error: @@ -2047,9 +2652,9 @@ uint8_t prepare_single_output() { unsigned char versionSize; int addressOffset; unsigned char address[22]; - unsigned short version; // addr prefix, or net id + unsigned short version; // addr prefix, or net id unsigned short textSize; - unsigned char script_version[2]; // Decred thing + unsigned char script_version[2]; // Decred thing vars.tmp.fullAddress[0] = '\0'; btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); @@ -2060,21 +2665,16 @@ uint8_t prepare_single_output() { PRINTF("amount: %.*H\n", 8, amount); - if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + - offset)) { + if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset)) { strcpy(vars.tmp.fullAddress, "OP_RETURN"); - } - else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + - offset)) { + } else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)) { addressOffset = offset + 4; version = btchip_context_D.payToAddressVersion; - } - else { + } else { addressOffset = offset + 3; version = btchip_context_D.payToScriptHashVersion; } if (vars.tmp.fullAddress[0] == 0) { - if (version > 255) { versionSize = 2; address[0] = (version >> 8); @@ -2083,13 +2683,15 @@ uint8_t prepare_single_output() { versionSize = 1; address[0] = version; } - os_memmove(address + versionSize, - btchip_context_D.currentOutput + addressOffset, 20); + os_memmove(address + versionSize, btchip_context_D.currentOutput + addressOffset, 20); // Prepare address - textSize = btchip_public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)tmp, - sizeof(tmp), version, 1); + textSize = btchip_public_key_to_encoded_base58(address, + 20 + versionSize, + (unsigned char *) tmp, + sizeof(tmp), + version, + 1); tmp[textSize] = '\0'; strcpy(vars.tmp.fullAddress, tmp); @@ -2097,15 +2699,14 @@ uint8_t prepare_single_output() { // Prepare amount - os_memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, + os_memmove(vars.tmp.fullAmount, + btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - btchip_context_D.shortCoinIdLength + 1); + (unsigned char *) (vars.tmp.fullAmount + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; return 1; } @@ -2119,7 +2720,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) { unsigned char amount[8], totalOutputAmount[8], fees[8]; char tmp[80]; unsigned char outputPos = 0, changeFound = 0; - unsigned char script_version[2]; // Decred thing + unsigned char script_version[2]; // Decred thing if (btchip_context_D.transactionContext.relaxed && !btchip_context_D.transactionContext.consumeP2SH) { @@ -2161,20 +2762,17 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); transaction_amount_add_be(totalOutputAmount, totalOutputAmount, amount); - offset += 8; // skip amount + offset += 8; // skip amount btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version - - isOpReturn = btchip_output_script_is_op_return( - btchip_context_D.currentOutput + offset); - isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + - offset); - isOpCreate = btchip_output_script_is_op_create( - btchip_context_D.currentOutput + offset); - isOpCall = btchip_output_script_is_op_call( - btchip_context_D.currentOutput + offset); - PRINTF("REGULAR SCRIPT: %d\n", btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); + offset += 2; // skip script_version + + isOpReturn = btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset); + isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + offset); + isOpCreate = btchip_output_script_is_op_create(btchip_context_D.currentOutput + offset); + isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + offset); + PRINTF("REGULAR SCRIPT: %d\n", + btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); // Always notify OP_RETURN to the user if (nullAmount && isOpReturn) { if (!checkOnly) { @@ -2182,17 +2780,14 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } goto error; } - if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + - offset) && - !isP2sh && !(nullAmount && isOpReturn) && - (!isOpCreate && !isOpCall)) { + if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + offset) && !isP2sh && + !(nullAmount && isOpReturn) && (!isOpCreate && !isOpCall)) { if (!checkOnly) { PRINTF("Error : Unrecognized input script"); } goto error; - } else if (!btchip_output_script_is_regular( - btchip_context_D.currentOutput + offset) && - !isP2sh && !(nullAmount && isOpReturn)) { + } else if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + offset) && + !isP2sh && !(nullAmount && isOpReturn)) { if (!checkOnly) { PRINTF("Error : Unrecognized input script"); } @@ -2200,10 +2795,8 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { unsigned char addressOffset = - (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (os_memcmp(btchip_context_D.currentOutput + offset + - addressOffset, + (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (os_memcmp(btchip_context_D.currentOutput + offset + addressOffset, btchip_context_D.tmpCtx.output.changeAddress + 1, 20) == 0) { if (changeFound) { @@ -2227,9 +2820,9 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } goto error; } - if (transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - totalOutputAmount)) { + if (transaction_amount_sub_be(fees, + btchip_context_D.transactionContext.transactionAmount, + totalOutputAmount)) { PRINTF("tx_amount: ", 8, btchip_context_D.transactionContext.transactionAmount); PRINTF("total_amount: ", 8, totalOutputAmount); if (!checkOnly) { @@ -2241,48 +2834,51 @@ uint8_t prepare_full_output(uint8_t checkOnly) { // Format validation message currentPos = 0; offset = 1; - btchip_context_D.tmp = (unsigned char *)tmp; + btchip_context_D.tmp = (unsigned char *) tmp; for (i = 0; i < numberOutputs; i++) { - if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + 2)) { + if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + + 2)) { unsigned char versionSize; int addressOffset; unsigned char address[22]; unsigned short version; btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); - offset += 8; // skip amount + offset += 8; // skip amount btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version + offset += 2; // skip script_version - if (btchip_output_script_is_regular( - btchip_context_D.currentOutput + offset)) { + if (btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)) { addressOffset = offset + 4; version = btchip_context_D.payToAddressVersion; - } else { + } else { addressOffset = offset + 3; version = btchip_context_D.payToScriptHashVersion; } - if (version > 255) { + if (version > 255) { versionSize = 2; address[0] = (version >> 8); address[1] = version; - } else { + } else { versionSize = 1; address[0] = version; } os_memmove(address + versionSize, - btchip_context_D.currentOutput + addressOffset, - 20); + btchip_context_D.currentOutput + addressOffset, + 20); // if we're processing the real output (not the change one) if (currentPos == outputPos) { unsigned short textSize = 0; // Prepare address - textSize = btchip_public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)tmp, - sizeof(tmp), version, 1); + textSize = btchip_public_key_to_encoded_base58(address, + 20 + versionSize, + (unsigned char *) tmp, + sizeof(tmp), + version, + 1); tmp[textSize] = '\0'; strcpy(vars.tmp.fullAddress, tmp); @@ -2293,34 +2889,24 @@ uint8_t prepare_full_output(uint8_t checkOnly) { os_memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); - vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = - ' '; + vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - btchip_context_D.shortCoinIdLength + - 1); + (unsigned char *) (vars.tmp.fullAmount + + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp - .fullAmount[textSize + - btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; // prepare fee display PRINTF("prepare fee display\n"); os_memmove(vars.tmp.feesAmount, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); - vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = - ' '; + vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - btchip_context_D.shortCoinIdLength + - 1); + (unsigned char *) (vars.tmp.feesAmount + + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp - .feesAmount[textSize + - btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; break; } } else { @@ -2340,11 +2926,20 @@ uint8_t prepare_full_output(uint8_t checkOnly) { uint8_t prepare_message_signature() { uint8_t buffer[32]; - cx_hash(&btchip_context_D.transactionHashWitness.header, CX_LAST, - vars.tmp.fullAmount, 0, buffer, 32); - - snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H...%.*H", - 8, buffer, 8, buffer + 32 - 8); + cx_hash(&btchip_context_D.transactionHashWitness.header, + CX_LAST, + vars.tmp.fullAmount, + 0, + buffer, + 32); + + snprintf(vars.tmp.fullAddress, + sizeof(vars.tmp.fullAddress), + "%.*H...%.*H", + 8, + buffer, + 8, + buffer + 32 - 8); return 1; } @@ -2361,7 +2956,7 @@ unsigned int btchip_bagl_confirm_full_output() { UX_DISPLAY(ui_verify_nanos, ui_verify_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_confirm_full_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } @@ -2378,9 +2973,10 @@ unsigned int btchip_bagl_confirm_single_output() { return 0; } - snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + - 1); + snprintf(vars.tmp.feesAmount, + sizeof(vars.tmp.feesAmount), + "output #%d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1); #if defined(TARGET_BLUE) ui_transaction_output_blue_init(); @@ -2390,7 +2986,7 @@ unsigned int btchip_bagl_confirm_single_output() { UX_DISPLAY(ui_verify_output_nanos, ui_verify_output_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_confirm_single_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } @@ -2407,7 +3003,7 @@ unsigned int btchip_bagl_finalize_tx() { UX_DISPLAY(ui_finalize_nanos, ui_finalize_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_finalize_flow, NULL); -#endif // TARGET_NANOX +#endif // TARGET_NANOX return 1; } @@ -2424,40 +3020,43 @@ void btchip_bagl_confirm_message_signature() { UX_DISPLAY(ui_verify_message_signature_nanos, ui_verify_message_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_sign_flow, NULL); -#endif // TARGET_NANOX +#endif // TARGET_NANOX } -void btchip_bagl_display_public_key(unsigned char* derivation_path) { +void btchip_bagl_display_public_key(unsigned char *derivation_path) { // append a white space at the end of the address to avoid glitch on nano S strcat(G_io_apdu_buffer + 200, " "); - bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); + bip32_print_path(derivation_path, + vars.tmp_warning.derivation_path, + MAX_DERIV_PATH_ASCII_LENGTH); uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); #if defined(TARGET_BLUE) - if(is_derivation_path_unusual){ + if (is_derivation_path_unusual) { UX_DISPLAY(ui_display_derivation_warning, ui_request_change_path_approval_blue_prepro); - } - else{ + } else { load_qr_code(G_io_apdu_buffer + 200); - UX_DISPLAY(ui_display_address_blue, ui_display_address_blue_prepro); + UX_DISPLAY(ui_display_address_blue, ui_display_address_blue_prepro); } #elif defined(TARGET_NANOS) // prepend a white space to the address G_io_apdu_buffer[199] = ' '; - ux_step = is_derivation_path_unusual?0:4; + ux_step = is_derivation_path_unusual ? 0 : 4; ux_step_count = 6; UX_DISPLAY(ui_display_address_nanos, ui_display_address_nanos_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, is_derivation_path_unusual?ux_display_public_with_warning_flow:ux_display_public_flow, NULL); -#endif // TARGET_NANOX + ux_flow_init( + 0, + is_derivation_path_unusual ? ux_display_public_with_warning_flow : ux_display_public_flow, + NULL); +#endif // TARGET_NANOX } -void btchip_bagl_display_token() -{ +void btchip_bagl_display_token() { #if defined(TARGET_BLUE) UX_DISPLAY(ui_display_token_blue, ui_display_token_blue_prepro); #elif defined(TARGET_NANOS) @@ -2466,13 +3065,12 @@ void btchip_bagl_display_token() UX_DISPLAY(ui_display_token_nanos, NULL); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_display_token_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } -void btchip_bagl_request_pubkey_approval() -{ +void btchip_bagl_request_pubkey_approval() { #if defined(TARGET_BLUE) - UX_DISPLAY(ui_request_pubkey_approval_blue, ui_request_pubkey_approval_blue_prepro); + UX_DISPLAY(ui_request_pubkey_approval_blue, ui_request_pubkey_approval_blue_prepro); #elif defined(TARGET_NANOS) // append and prepend a white space to the address ux_step = 0; @@ -2480,13 +3078,12 @@ void btchip_bagl_request_pubkey_approval() UX_DISPLAY(ui_request_pubkey_approval_nanos, NULL); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } -void btchip_bagl_request_change_path_approval(unsigned char* change_path) -{ +void btchip_bagl_request_change_path_approval(unsigned char *change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); - #if defined(TARGET_BLUE) +#if defined(TARGET_BLUE) UX_DISPLAY(ui_request_change_path_approval_blue, ui_request_change_path_approval_blue_prepro); #elif defined(TARGET_NANOS) // append and prepend a white space to the address @@ -2495,7 +3092,7 @@ void btchip_bagl_request_change_path_approval(unsigned char* change_path) UX_DISPLAY(ui_request_change_path_approval_nanos, ui_request_change_path_approval_nanos_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_request_change_path_approval_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } void app_exit(void) { @@ -2519,17 +3116,17 @@ btchip_altcoin_config_t const C_coin_config = { .header_text = COIN_COINID_HEADER, .color_header = COIN_COLOR_HDR, .color_dashboard = COIN_COLOR_DB, -#endif // TARGET_BLUE +#endif // TARGET_BLUE .coinid = COIN_COINID, .name = COIN_COINID_NAME, .name_short = COIN_COINID_SHORT, #ifdef COIN_FORKID .forkid = COIN_FORKID, -#endif // COIN_FORKID +#endif // COIN_FORKID #ifdef COIN_FLAGS .flags = COIN_FLAGS, -#endif // COIN_FLAGS +#endif // COIN_FLAGS .kind = COIN_KIND, }; @@ -2544,18 +3141,18 @@ __attribute__((section(".boot"))) int main(int arg0) { strcpy(name, COIN_COINID_NAME); unsigned char name_short[sizeof(COIN_COINID_SHORT)]; strcpy(name_short, COIN_COINID_SHORT); - #ifdef TARGET_BLUE - unsigned char header[sizeof(COIN_COINID_HEADER)]; - strcpy(header, COIN_COINID_HEADER); - #endif // TARGET_BLUE +#ifdef TARGET_BLUE + unsigned char header[sizeof(COIN_COINID_HEADER)]; + strcpy(header, COIN_COINID_HEADER); +#endif // TARGET_BLUE btchip_altcoin_config_t coin_config; os_memmove(&coin_config, &C_coin_config, sizeof(coin_config)); - #ifdef TARGET_BLUE - coin_config.header_text = header; - coin_config.color_header = COIN_COLOR_HDR; - coin_config.color_dashboard = COIN_COLOR_DB; - #endif // TARGET_BLUE +#ifdef TARGET_BLUE + coin_config.header_text = header; + coin_config.color_header = COIN_COLOR_HDR; + coin_config.color_dashboard = COIN_COLOR_DB; +#endif // TARGET_BLUE coin_config.coinid = coinid; coin_config.name = name; coin_config.name_short = name_short; @@ -2566,7 +3163,7 @@ __attribute__((section(".boot"))) int main(int arg0) { check_api_level(CX_COMPAT_APILEVEL); // delegate to bitcoin app/lib libcall_params[0] = "Decred"; - libcall_params[1] = 0x100; // use the Init call, as we won't exit + libcall_params[1] = 0x100; // use the Init call, as we won't exit libcall_params[2] = &coin_config; os_lib_call(&libcall_params); } @@ -2582,14 +3179,14 @@ __attribute__((section(".boot"))) int main(int arg0) { if (arg0) { // is ID 1 ? - if (((unsigned int *)arg0)[0] != 0x100) { + if (((unsigned int *) arg0)[0] != 0x100) { app_exit(); return 0; } // grab the coin config structure from the first parameter - G_coin_config = (btchip_altcoin_config_t *)((unsigned int *)arg0)[1]; + G_coin_config = (btchip_altcoin_config_t *) ((unsigned int *) arg0)[1]; } else { - G_coin_config = (btchip_altcoin_config_t *)PIC(&C_coin_config); + G_coin_config = (btchip_altcoin_config_t *) PIC(&C_coin_config); } // ensure exception will work as planned @@ -2604,7 +3201,7 @@ __attribute__((section(".boot"))) int main(int arg0) { #ifdef TARGET_NANOX // grab the current plane mode setting G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX +#endif // TARGET_NANOX btchip_context_init(); @@ -2616,13 +3213,13 @@ __attribute__((section(".boot"))) int main(int arg0) { #ifdef HAVE_BLE BLE_power(0, NULL); BLE_power(1, "Nano X"); -#endif // HAVE_BLE +#endif // HAVE_BLE #if defined(TARGET_BLUE) // setup the status bar colors (remembered after wards, even // more if another app does not resetup after app switch) UX_SET_STATUS_BAR_COLOR(COLOR_WHITE, G_coin_config->color_header); -#endif // TARGET_ID +#endif // TARGET_ID app_main(); } @@ -2641,6 +3238,6 @@ __attribute__((section(".boot"))) int main(int arg0) { END_TRY; } app_exit(); -#endif // USE_LIB_DECRED +#endif // USE_LIB_DECRED return 0; } From ea86328b7cec2167d13dd0249e28d45c30fb693c Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 22 Nov 2022 16:43:51 +0100 Subject: [PATCH 02/41] Update Makefile for Stax compatibility. --- Makefile | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) mode change 100755 => 100644 Makefile diff --git a/Makefile b/Makefile old mode 100755 new mode 100644 index f127565..3099d8e --- a/Makefile +++ b/Makefile @@ -63,6 +63,8 @@ ifeq ($(TARGET_NAME),TARGET_BLUE) ICONNAME=blue_app_$(COIN).gif else ifeq ($(TARGET_NAME),TARGET_NANOS) ICONNAME=nanos_app_$(COIN).gif +else ifeq ($(TARGET_NAME),TARGET_FATSTACKS) +ICONNAME=stax_app_$(COIN).bmp else ICONNAME=nanox_app_$(COIN).gif endif @@ -76,8 +78,13 @@ all: default # Platform # ############ +ifneq ($(TARGET_NAME),TARGET_FATSTACKS) + DEFINES += HAVE_BAGL + DEFINES += NBGL_QRCODE +endif + DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300 -DEFINES += HAVE_BAGL HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U +DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) TCS_LOADER_PATCH_VERSION=0 @@ -102,7 +109,9 @@ endif ifneq ($(TARGET_NAME),TARGET_NANOS) DEFINES += HAVE_GLO096 -DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 +ifneq ($(TARGET_NAME),TARGET_FATSTACKS) +DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 +endif DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX @@ -159,7 +168,13 @@ include $(BOLOS_SDK)/Makefile.glyphs ### variables processed by the common makefile.rules of the SDK to grab source files and include dirs APP_SOURCE_PATH += src SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f qrcode -SDK_SOURCE_PATH += lib_ux + +ifeq ($(TARGET_NAME),TARGET_FATSTACKS) +SDK_SOURCE_PATH += lib_nbgl/src +SDK_SOURCE_PATH += lib_nbgl/src +else +SDK_SOURCE_PATH += lib_ux +endif ifeq ($(TARGET_NAME),TARGET_NANOX) SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl From d32adf520f5b56493e1526390f6394f98bff23e9 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 22 Nov 2022 16:47:09 +0100 Subject: [PATCH 03/41] Remove obsolete Blue specific code. --- Makefile | 4 +- include/btchip_context.h | 5 - src/btchip_helpers.c | 11 - src/main.c | 1513 +------------------------------------- 4 files changed, 13 insertions(+), 1520 deletions(-) mode change 100644 => 100755 Makefile diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index 3099d8e..7b0d89d --- a/Makefile +++ b/Makefile @@ -59,9 +59,7 @@ endif APP_LOAD_PARAMS += $(APP_LOAD_FLAGS) DEFINES += $(DEFINES_LIB) -ifeq ($(TARGET_NAME),TARGET_BLUE) -ICONNAME=blue_app_$(COIN).gif -else ifeq ($(TARGET_NAME),TARGET_NANOS) +ifeq ($(TARGET_NAME),TARGET_NANOS) ICONNAME=nanos_app_$(COIN).gif else ifeq ($(TARGET_NAME),TARGET_FATSTACKS) ICONNAME=stax_app_$(COIN).bmp diff --git a/include/btchip_context.h b/include/btchip_context.h index 38031ac..152964e 100644 --- a/include/btchip_context.h +++ b/include/btchip_context.h @@ -236,11 +236,6 @@ typedef struct btchip_altcoin_config_s { unsigned short p2sh_version; unsigned char family; //unsigned char* iconsuffix;// will use the icon provided on the stack (maybe) - #ifdef TARGET_BLUE - const char* header_text; - unsigned int color_header; - unsigned int color_dashboard; - #endif // TARGET_BLUE const char* coinid; // used coind id for message signature prefix const char* name; // for ux displays const char* name_short; // for unit in ux displays diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 28a63df..be25178 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -335,17 +335,6 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char *out, unsigned cha // remove last '/' out[offset - 1] = '\0'; -#if defined(TARGET_BLUE) - // if the path is longer than 30 char, split the string in multiple strings of length 30 - uint8_t len = strnlen(out, MAX_DERIV_PATH_ASCII_LENGTH); - uint8_t num_split = len / 30; - - for (i = 1; i <= num_split; i++) { - os_memmove(out + 30 * i, out + (30 * i - 1), len - 29 * i); - out[30 * i - 1] = '\0'; - } -#endif - return offset - 1; } diff --git a/src/main.c b/src/main.c index 083212c..c8d8a89 100644 --- a/src/main.c +++ b/src/main.c @@ -97,261 +97,6 @@ unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; (char *) text, 0, 0, 0, NULL, NULL, NULL \ } -#define UI_BLUE_BACKGROUND(title) \ - {{BAGL_RECTANGLE, 0x00, 0, 68, 320, 413, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BLACK, 0, 0}, \ - NULL, \ - 0, \ - 0, \ - 0, \ - NULL, \ - NULL, \ - NULL}, \ - {{BAGL_RECTANGLE, 0x00, 0, 20, 320, 48, 0, 0, BAGL_FILL, COLOR_APP, COLOR_APP, 0, 0}, \ - NULL, \ - 0, \ - 0, \ - 0, \ - NULL, \ - NULL, \ - NULL}, \ - { \ - {BAGL_LABELINE, \ - 0x01, \ - 0, \ - 45, \ - 320, \ - 30, \ - 0, \ - 0, \ - BAGL_FILL, \ - COLOR_WHITE, \ - COLOR_APP, \ - BAGL_FONT_OPEN_SANS_SEMIBOLD_10_13PX | BAGL_FONT_ALIGNMENT_CENTER, \ - 0}, \ - title, 0, 0, 0, NULL, NULL, NULL \ - } -#define UI_BLUE_BUTTON_SETTINGS(setting_cb) \ - { \ - {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ - 0x00, \ - 0, \ - 19, \ - 56, \ - 44, \ - 0, \ - 0, \ - BAGL_FILL, \ - COLOR_APP, \ - COLOR_APP_LIGHT, \ - BAGL_FONT_SYMBOLS_0 | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, \ - 0}, \ - BAGL_FONT_SYMBOLS_0_SETTINGS, 0, COLOR_APP, COLOR_WHITE, setting_cb, NULL, NULL \ - } -#define UI_BLUE_BUTTON_GO_BACK(back_cb) \ - { \ - {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ - 0x00, \ - 0, \ - 19, \ - 50, \ - 44, \ - 0, \ - 0, \ - BAGL_FILL, \ - COLOR_APP, \ - COLOR_APP_LIGHT, \ - BAGL_FONT_SYMBOLS_0 | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, \ - 0}, \ - BAGL_FONT_SYMBOLS_0_LEFT, 0, COLOR_APP, COLOR_WHITE, back_cb, NULL, NULL \ - } -#define UI_BLUE_ICON(userid, x, y, width, height, icon, bg_color) \ - { \ - {BAGL_ICON, userid, x, y, width, height, 0, 0, BAGL_FILL, 0, bg_color, 0, 0}, icon, 0, 0, \ - 0, NULL, NULL, NULL \ - } -// Toggle icon should be set/updated within a preprocessor -#define UI_BLUE_TOGGLE(x, y, bg_color) \ - { \ - {BAGL_ICON, 0x01, x, y, 320, 18, 0, 0, BAGL_FILL, COLOR_BLACK, bg_color, 0, 0}, NULL, 0, \ - 0, 0, NULL, NULL, NULL \ - } -#define UI_BLUE_TOUCHZONE(x, y, x_max, y_max, tap_cb, out_cb, over_cb) \ - { \ - {BAGL_NONE | BAGL_FLAG_TOUCHABLE, \ - 0x00, \ - x, \ - y, \ - x_max, \ - y_max, \ - 0, \ - 0, \ - BAGL_FILL, \ - COLOR_WHITE, \ - COLOR_BLACK, \ - 0, \ - 0}, \ - NULL, 0, COLOR_LIGHT_GRAY, COLOR_BLACK, tap_cb, out_cb, over_cb \ - } -#define UI_BLUE_BUTTON_EXIT(exit_cb) \ - { \ - {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ - 0x00, \ - 264, \ - 19, \ - 56, \ - 44, \ - 0, \ - 0, \ - BAGL_FILL, \ - COLOR_APP, \ - COLOR_APP_LIGHT, \ - BAGL_FONT_SYMBOLS_0 | BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, \ - 0}, \ - BAGL_FONT_SYMBOLS_0_DASHBOARD, 0, COLOR_APP, COLOR_WHITE, exit_cb, NULL, NULL \ - } -// Displays standard interface for approval: 2 buttons at the bottom of the screen, one to cancel -// and one to proceed -#define UI_BLUE_BUTTONS_REJECT_OR_CONFIRM(reject_text, confirm_text, reject_cb, confirm_cb) \ - {{BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ - 0x00, \ - 40, \ - 414, \ - 115, \ - 36, \ - 0, \ - 18, \ - BAGL_FILL, \ - 0xCCCCCC, \ - COLOR_BG_1, \ - BAGL_FONT_OPEN_SANS_REGULAR_11_14PX | BAGL_FONT_ALIGNMENT_CENTER | \ - BAGL_FONT_ALIGNMENT_MIDDLE, \ - 0}, \ - reject_text, \ - 0, \ - 0xB7B7B7, \ - COLOR_BG_1, \ - reject_cb, \ - NULL, \ - NULL}, \ - { \ - {BAGL_RECTANGLE | BAGL_FLAG_TOUCHABLE, \ - 0x00, \ - 165, \ - 414, \ - 115, \ - 36, \ - 0, \ - 18, \ - BAGL_FILL, \ - 0x41ccb4, \ - COLOR_BG_1, \ - BAGL_FONT_OPEN_SANS_REGULAR_11_14PX | BAGL_FONT_ALIGNMENT_CENTER | \ - BAGL_FONT_ALIGNMENT_MIDDLE, \ - 0}, \ - confirm_text, 0, 0x3ab7a2, COLOR_BG_1, confirm_cb, NULL, NULL \ - } -#define UI_BLUE_TEXT(userid, x, y, w, text, font, flags, text_color, bg_color) \ - { \ - {BAGL_LABELINE, \ - userid, \ - x, \ - y, \ - w, \ - 30, \ - 0, \ - 0, \ - BAGL_FILL, \ - text_color, \ - bg_color, \ - font | flags, \ - 0}, \ - (char *) text, 0, 0, 0, NULL, NULL, NULL \ - } - -#if defined(TARGET_BLUE) -#include "qrcodegen.h" - -union { - struct { - char addressSummary[40]; // beginning of the output address ... end of - char fullAmount[65]; // full amount - char fullAddress[65]; - // the address - char feesAmount[40]; // fees - char output_numbering[10]; - } tmp; - - struct { - char addressSummary[MAX_CHAR_PER_LINE + 1]; - bagl_icon_details_t icon_details; - unsigned int colors[2]; - unsigned char qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(3)]; - } tmpqr; - - struct { - // A bip44 path contains 5 elements, which max length in ascii is 10 char + optional quote - // "'" + "/" + \0" - char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; - } tmp_warning; - - unsigned int dummy; // ensure the whole vars is aligned for the CM0 to - // operate correctly -} vars; - -void load_qr_code(unsigned char *data) { - // must assert spi buffer is longer than the requested qrcode len. - // sizeof(data and temp buffer) >= - // qrcodegen_BUFFER_LEN_FOR_VERSION(guessed_qrcode_version) - - // encode the address as a QRcode - os_memset(&vars.tmpqr, 0, sizeof(vars.tmpqr)); - // use G_io_seproxyhal_spi_buffer as - if (qrcodegen_encodeBinary(data, - strlen(data), - G_io_seproxyhal_spi_buffer, - sizeof(G_io_seproxyhal_spi_buffer), - // the edge qrcode size will be discarded when drawing - &vars.tmpqr.qrcode, - sizeof(vars.tmpqr.qrcode), - qrcodegen_Ecc_LOW, - qrcodegen_VERSION_MIN, - 3, // buffer is not designed to handle more than version 3 - qrcodegen_Mask_AUTO, - 0)) { - vars.tmpqr.icon_details.width = vars.tmpqr.qrcode[0]; - vars.tmpqr.icon_details.height = vars.tmpqr.qrcode[0]; - vars.tmpqr.icon_details.bpp = 1; - - // magnify on the fly without consuming RAM - vars.tmpqr.colors[0] = -1; - - vars.tmpqr.icon_details.colors = &vars.tmpqr.colors[0]; - vars.tmpqr.icon_details.bitmap = &vars.tmpqr.qrcode[1]; - // os_memmove(&vars.tmpqr.icon, &C_qrcode_icon_initializer, - // sizeof(C_qrcode_icon_initializer)); - } -} - -unsigned int map_color(unsigned int color) { - switch (color) { - case COLOR_APP: - return G_coin_config->color_header; - - case COLOR_APP_LIGHT: - return G_coin_config->color_dashboard; - } - return color; -} -void copy_element_and_map_coin_colors(const bagl_element_t *element) { - os_memmove(&tmp_element, element, sizeof(bagl_element_t)); - tmp_element.component.fgcolor = map_color(tmp_element.component.fgcolor); - tmp_element.component.bgcolor = map_color(tmp_element.component.bgcolor); - tmp_element.overfgcolor = map_color(tmp_element.overfgcolor); - tmp_element.overbgcolor = map_color(tmp_element.overbgcolor); -} - -#else - union { struct { // char addressSummary[40]; // beginning of the output address ... end @@ -377,7 +122,6 @@ union { operate correctly */ } vars; -#endif unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e); @@ -385,7 +129,6 @@ unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_elem unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_display_address_blue(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e); @@ -411,1104 +154,6 @@ const bagl_element_t *ui_menu_item_out_over(const bagl_element_t *e) { return e; } -#if defined(TARGET_BLUE) - -const bagl_element_t *ui_idle_blue_prepro(const bagl_element_t *element) { - copy_element_and_map_coin_colors(element); - if (element->component.userid == 0x01) { - tmp_element.text = G_coin_config->header_text; - } - return &tmp_element; -} - -const bagl_element_t ui_idle_blue[] = { - - UI_BLUE_BACKGROUND(NULL), - UI_BLUE_BUTTON_SETTINGS(io_seproxyhal_touch_settings), - UI_BLUE_BUTTON_EXIT(io_seproxyhal_touch_exit), - UI_BLUE_TEXT(0, - 0, - 270, - 320, - "Open your wallet", - BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 308, - 320, - "Connect your Ledger Blue and open your", - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 331, - 320, - "preferred wallet to view your accounts.", - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 450, - 320, - "Validation requests will show automatically.", - BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_GRAY, - COLOR_BG_1) - -}; - -unsigned int ui_idle_blue_button(unsigned int button_mask, unsigned int button_mask_counter) { - return 0; -} - -const bagl_element_t *ui_settings_blue_toggle_pubKeyRequestRestriction(const bagl_element_t *e) { - // swap setting and request redraw of settings elements - uint8_t setting = N_btchip.pubKeyRequestRestriction ? 0 : 1; - nvm_write(&N_btchip.pubKeyRequestRestriction, (void *) &setting, sizeof(uint8_t)); - // only refresh settings mutable drawn elements - UX_REDISPLAY_IDX(7); - // won't redisplay the bagl_none - return 0; -} -// don't perform any draw/color change upon finger event over settings -const bagl_element_t *ui_settings_out_over(const bagl_element_t *e) { - return NULL; -} -unsigned int ui_settings_back_callback(const bagl_element_t *e) { - // go back to idle - ui_idle(); - return 0; -} -const bagl_element_t ui_settings_blue[] = { - UI_BLUE_BACKGROUND("SETTINGS"), - UI_BLUE_BUTTON_GO_BACK(ui_settings_back_callback), - UI_BLUE_TEXT(0, - 30, - 105, - 160, - "Public key export", - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 30, - 126, - 260, - "Enable to approve export requests manually", - BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_GRAY, - COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, - 78, - 320, - 68, - ui_settings_blue_toggle_pubKeyRequestRestriction, - ui_settings_out_over, - ui_settings_out_over), - UI_BLUE_TOGGLE(258, 98, COLOR_BG_1)}; -const bagl_element_t *ui_settings_blue_prepro(const bagl_element_t *e) { - copy_element_and_map_coin_colors(e); - // none elements are skipped - if ((e->component.type & (~BAGL_FLAG_TOUCHABLE)) == BAGL_NONE) { - return 0; - } - // swap icon buffer to be displayed depending on if corresponding setting is enabled or not. - if (e->component.userid) { - switch (e->component.userid) { - case 0x01: - // swap icon content - if (N_btchip.pubKeyRequestRestriction) { - tmp_element.text = &C_blue_icon_toggle_set; - } else { - tmp_element.text = &C_blue_icon_toggle_reset; - } - break; - } - } - return &tmp_element; -} - -unsigned int ui_settings_blue_button(unsigned int button_mask, unsigned int button_mask_counter) { - return 0; -} - -#endif // #if defined(TARGET_BLUE) - -#if defined(TARGET_NANOS) - -const ux_menu_entry_t menu_main[]; -const ux_menu_entry_t menu_settings[]; - -// change the setting -void menu_settings_pubKeyRequestRestriction_change(unsigned int enabled) { - nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &enabled, 1); - // go back to the menu entry - UX_MENU_DISPLAY(0, menu_main, NULL); -} -const ux_menu_entry_t menu_settings_pubKeyRequestRestriction[] = { - {NULL, menu_settings_pubKeyRequestRestriction_change, 1, NULL, "Manual approval", NULL, 0, 0}, - {NULL, menu_settings_pubKeyRequestRestriction_change, 0, NULL, "Auto approval", NULL, 0, 0}, - UX_MENU_END}; -const ux_menu_entry_t menu_settings[] = { - {menu_settings_pubKeyRequestRestriction, NULL, 0, NULL, "Public keys", "export approval", 0, 0}, - {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, - UX_MENU_END}; - -const ux_menu_entry_t menu_about[] = { - {NULL, NULL, 0, NULL, "Version", APPVERSION, 0, 0}, - {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, - UX_MENU_END}; - -const ux_menu_entry_t menu_main[] = { - //{NULL, NULL, 0, &NAME3(C_nanos_badge_, COINID, ), "Use wallet to", "view - // accounts", 33, 12}, - {NULL, NULL, 0, NULL, "Use wallet to", "view accounts", 0, 0}, - {menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0}, - {menu_about, NULL, 0, NULL, "About", NULL, 0, 0}, - {NULL, os_sched_exit, 0, &C_nanos_icon_dashboard, "Quit app", NULL, 50, 29}, - UX_MENU_END}; - -#endif // #if defined(TARGET_NANOS) - -#if defined(TARGET_BLUE) -// reuse vars.tmp.addressSummary for each line content -typedef void (*callback_t)(void); -callback_t ui_details_back_callback; - -const char *ui_details_title; -const char *ui_details_content; - -const bagl_element_t *ui_details_blue_back_callback(const bagl_element_t *element) { - ui_details_back_callback(); - return 0; -} - -const bagl_element_t ui_details_blue[] = {UI_BLUE_BACKGROUND(NULL), - UI_BLUE_BUTTON_GO_BACK(ui_details_blue_back_callback), - UI_BLUE_TEXT(0, - 30, - 106, - 320, - "VALUE", - BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_GRAY, - COLOR_BG_1), - UI_BLUE_TEXT(0x10, - 30, - 136, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x11, - 30, - 159, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x12, - 30, - 182, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x13, - 30, - 205, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x14, - 30, - 228, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x15, - 30, - 251, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x16, - 30, - 274, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x17, - 30, - 297, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x18, - 30, - 320, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_BLACK, - COLOR_BG_1), - //"..." at the end if too much - UI_BLUE_TEXT(0x19, - 30, - 343, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_GRAY, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 450, - 320, - "Review the whole value before continuing.", - BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_GRAY, - COLOR_BG_1)}; - -const bagl_element_t *ui_details_blue_prepro(const bagl_element_t *element) { - copy_element_and_map_coin_colors(element); - if (element->component.userid == 1) { - tmp_element.text = ui_details_title; - return &tmp_element; - } else if (element->component.userid > 0) { - unsigned int length = strlen(ui_details_content); - if (length >= (element->component.userid & 0xF) * MAX_CHAR_PER_LINE) { - os_memset(vars.tmp.addressSummary, 0, MAX_CHAR_PER_LINE + 1); - os_memmove(vars.tmp.addressSummary, - ui_details_content + (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, - MIN(length - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, - MAX_CHAR_PER_LINE)); - return 1; - } - // nothing to draw for this line - return 0; - } - return &tmp_element; -} - -unsigned int ui_details_blue_button(unsigned int button_mask, unsigned int button_mask_counter) { - return 0; -} - -void ui_details_init(const char *title, const char *content, callback_t back_callback) { - ui_details_title = title; - ui_details_content = content; - ui_details_back_callback = back_callback; - UX_DISPLAY(ui_details_blue, ui_details_blue_prepro); -} - -// redisplay transaction validation when exiting the details -void ui_transaction_blue_init(void); - -bagl_element_callback_t ui_transaction_blue_ok; -bagl_element_callback_t ui_transaction_blue_cancel; - -const bagl_element_t *ui_transaction_blue_ok_callback(const bagl_element_t *e) { - return ui_transaction_blue_ok(e); -} - -const bagl_element_t *ui_transaction_blue_cancel_callback(const bagl_element_t *e) { - return ui_transaction_blue_cancel(e); -} - -typedef enum { - TRANSACTION_FULL, - TRANSACTION_OUTPUT, - TRANSACTION_FINALIZE, - TRANSACTION_P2SH, - TRANSACTION_MESSAGE, -} ui_transaction_blue_state_t; -ui_transaction_blue_state_t G_ui_transaction_blue_state; -// pointer to value to be displayed -const char *ui_transaction_blue_values[3]; -// variable part of the structure -const char *const ui_transaction_blue_details_name[][5] = { - /*TRANSACTION_FULL*/ - { - "AMOUNT", - "ADDRESS", - "FEES", - "CONFIRM TRANSACTION", - "Transaction details", - }, - - /*TRANSACTION_OUTPUT*/ - { - "OUTPUT#", - "ADDRESS", - "AMOUNT", - "CONFIRM OUTPUT", - "Transaction output", - }, - - /*TRANSACTION_FINALIZE*/ - {"AMOUNT", "FEES", NULL, "CONFIRM TRANSACTION", "Transaction details"}, - - /*TRANSACTION_P2SH*/ - { - NULL, - NULL, - NULL, - "CONFIRM P2SH", - "P2SH Transaction", - }, - - /*TRANSACTION_MESSAGE*/ - { - "HASH", - NULL, - NULL, - "SIGN MESSAGE", - "Message signature", - }, -}; - -const bagl_element_t *ui_transaction_blue_1_details(const bagl_element_t *e) { - if (strlen(ui_transaction_blue_values[0]) * BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= - 160) { - // display details screen - ui_details_init(ui_transaction_blue_details_name[G_ui_transaction_blue_state][0], - ui_transaction_blue_values[0], - ui_transaction_blue_init); - } - return 0; -}; - -const bagl_element_t *ui_transaction_blue_2_details(const bagl_element_t *e) { - if (strlen(ui_transaction_blue_values[1]) * BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= - 160) { - ui_details_init(ui_transaction_blue_details_name[G_ui_transaction_blue_state][1], - ui_transaction_blue_values[1], - ui_transaction_blue_init); - } - return 0; -}; - -const bagl_element_t *ui_transaction_blue_3_details(const bagl_element_t *e) { - if (strlen(ui_transaction_blue_values[2]) * BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH >= - 160) { - ui_details_init(ui_transaction_blue_details_name[G_ui_transaction_blue_state][2], - ui_transaction_blue_values[2], - ui_transaction_blue_init); - } - return 0; -}; - -const bagl_element_t ui_transaction_blue[] = { - UI_BLUE_BACKGROUND(NULL), - UI_BLUE_TEXT(0, - 30, - 106, - 320, - "VALUE", - BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, - BAGL_FONT_ALIGNMENT_LEFT, - COLOR_GRAY, - COLOR_BG_1), - UI_BLUE_ICON(0x40, 30, 98, 50, 50, &C_blue_badge_transaction, COLOR_BG_1), - // becomes a line in preprocessor - UI_BLUE_TEXT(0x50, - 100, - 117, - 320, - NULL, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - 0, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 100, - 138, - 320, - "Check and confirm values", - BAGL_FONT_OPEN_SANS_REGULAR_8_11PX, - 0, - COLOR_GRAY, - COLOR_BG_1), - - // First detail zone - UI_BLUE_TEXT(0x70, - 30, - 196, - 100, - NULL, - BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, - 0, - COLOR_BLACK, - COLOR_BG_1), - // x-18 when ... - UI_BLUE_TEXT(0x10, - 130, - 200, - 160, - NULL, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_RIGHT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x20, - 284, - 196, - 6, - BAGL_FONT_SYMBOLS_0_MINIRIGHT, - BAGL_FONT_SYMBOLS_0, - BAGL_FONT_ALIGNMENT_RIGHT, - COLOR_GRAY, - COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, - 168, - 320, - 48, - ui_transaction_blue_1_details, - ui_menu_item_out_over, - ui_menu_item_out_over), - {{BAGL_RECTANGLE, 0x20, 0, 168, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0, 0}, - NULL, - 0, - 0x41CCB4, - 0, - NULL, - NULL, - NULL}, - - // separator when second details is to be displayed - {{BAGL_RECTANGLE, 0x31, 30, 216, 260, 1, 1, 0, 0, COLOR_LIGHT_GRAY, COLOR_BG_1, 0, 0}, - NULL, - 0, - 0, - 0, - NULL, - NULL, - NULL}, - UI_BLUE_TEXT(0x71, - 30, - 245, - 100, - NULL, - BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, - 0, - COLOR_BLACK, - COLOR_BG_1), - // x-18 when ... - UI_BLUE_TEXT(0x11, - 130, - 245, - 160, - NULL, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_RIGHT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x21, - 284, - 245, - 6, - BAGL_FONT_SYMBOLS_0_MINIRIGHT, - BAGL_FONT_SYMBOLS_0, - BAGL_FONT_ALIGNMENT_RIGHT, - COLOR_GRAY, - COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, - 217, - 320, - 48, - ui_transaction_blue_2_details, - ui_menu_item_out_over, - ui_menu_item_out_over), - {{BAGL_RECTANGLE, 0x21, 0, 217, 5, 48, 0, 0, BAGL_FILL, COLOR_BG_1, COLOR_BG_1, 0, 0}, - NULL, - 0, - 0x41CCB4, - 0, - NULL, - NULL, - NULL}, - - // separator when second details is to be displayed - {{BAGL_RECTANGLE, 0x32, 30, 265, 260, 1, 1, 0, 0, COLOR_LIGHT_GRAY, COLOR_BG_1, 0, 0}, - NULL, - 0, - 0, - 0, - NULL, - NULL, - NULL}, - UI_BLUE_TEXT(0x72, - 30, - 294, - 100, - NULL, - BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, - 0, - COLOR_BLACK, - COLOR_BG_1), - // x-18 when ... - UI_BLUE_TEXT(0x12, - 130, - 294, - 160, - NULL, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - BAGL_FONT_ALIGNMENT_RIGHT, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x22, - 284, - 294, - 6, - BAGL_FONT_SYMBOLS_0_MINIRIGHT, - BAGL_FONT_SYMBOLS_0, - BAGL_FONT_ALIGNMENT_RIGHT, - COLOR_GRAY, - COLOR_BG_1), - UI_BLUE_TOUCHZONE(0, - 266, - 320, - 48, - ui_transaction_blue_3_details, - ui_menu_item_out_over, - ui_menu_item_out_over), - {{BAGL_RECTANGLE, - 0x22, - 0, - 266, - 5, - 48, - 0, - 0, - BAGL_FILL, - COLOR_BG_1, - COLOR_BG_1, - 0, - 0}, // WHY OVER ACTIVATE WHE TOUCING OUT OF RECTANGLE ? ASK OTO - NULL, - 0, - 0x41CCB4, - 0, - NULL, - NULL, - NULL}, - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", - "CONFIRM", - ui_transaction_blue_cancel_callback, - ui_transaction_blue_ok_callback) - -}; - -const bagl_element_t *ui_transaction_blue_prepro(const bagl_element_t *element) { - copy_element_and_map_coin_colors(element); - if (element->component.userid == 0) { - return &tmp_element; - } - // none elements are skipped - if ((element->component.type & (~BAGL_FLAG_TOUCHABLE)) == BAGL_NONE) { - return 0; - } else { - switch (element->component.userid & 0xF0) { - // icon - case 0x40: - return &tmp_element; - break; - - // TITLE - case 0x60: - tmp_element.text = ui_transaction_blue_details_name[G_ui_transaction_blue_state][3]; - return &tmp_element; - break; - - // SUBLINE - case 0x50: - tmp_element.text = ui_transaction_blue_details_name[G_ui_transaction_blue_state][4]; - return &tmp_element; - break; - - // details label - case 0x70: - if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & 0xF]) { - return NULL; - } - tmp_element.text = - ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & 0xF]; - return &tmp_element; - - // detail value - case 0x10: - // won't display - if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & 0xF]) { - return NULL; - } - // always display the value - tmp_element.text = ui_transaction_blue_values[(element->component.userid & 0xF)]; - - // x -= 18 when overflow is detected - if (strlen(ui_transaction_blue_values[(element->component.userid & 0xF)]) * - BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH >= - 160) { - tmp_element.component.x -= 18; - } - return &tmp_element; - break; - - // right arrow and left selection rectangle - case 0x20: - if (!ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & 0xF]) { - return NULL; - } - if (strlen(ui_transaction_blue_values[(element->component.userid & 0xF)]) * - BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH < - 160) { - return NULL; - } - - // horizontal delimiter - case 0x30: - return ui_transaction_blue_details_name[G_ui_transaction_blue_state] - [element->component.userid & 0xF] != NULL - ? &tmp_element - : NULL; - } - } - return &tmp_element; -} -unsigned int ui_transaction_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) { - return 0; -} - -const bagl_element_t ui_display_derivation_warning[] = { - UI_BLUE_BACKGROUND("WARNING"), - - UI_BLUE_ICON(0x40, 135, 95, 50, 50, &C_blue_badge_warning, COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 185, - 320, - "The derivation path is unusual.", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 203, - 320, - "Reject if you're not sure.", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 220, - 320, - "Contact Ledger support for help.", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 271, - 320, - "Derivation path:", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 297, - 320, - vars.tmp_warning.derivation_path, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 314, - 320, - vars.tmp_warning.derivation_path + 30, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 331, - 320, - vars.tmp_warning.derivation_path + 60, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 348, - 320, - vars.tmp_warning.derivation_path + 90, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", - "CONFIRM", - io_seproxyhal_touch_display_cancel, - io_seproxyhal_touch_display_address_blue)}; - -const bagl_element_t ui_display_address_blue[] = { - UI_BLUE_BACKGROUND("CONFIRM ACCOUNT"), - UI_BLUE_TEXT(0, - 30, - 106, - 320, - "ACCOUNT", - BAGL_FONT_OPEN_SANS_SEMIBOLD_8_11PX, - 0, - COLOR_GRAY, - COLOR_BG_1), - - UI_BLUE_TEXT(0x10, - 30, - 126, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - 0, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x11, - 30, - 139, - 260, - vars.tmp.addressSummary, - BAGL_FONT_OPEN_SANS_REGULAR_10_13PX, - 0, - COLOR_BLACK, - COLOR_BG_1), - - {{BAGL_RECTANGLE, - 0x02, - 320 / 2 - 0x1D * 8 / 2, - 150, - 8, - 8, - 0, - 0, - BAGL_FILL, - COLOR_WHITE, - COLOR_BLACK, - 0, - 0}, - NULL, - 0, - 0, - 0, - NULL, - NULL, - NULL}, - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", - "CONFIRM", - io_seproxyhal_touch_display_cancel, - io_seproxyhal_touch_display_ok)}; - -const bagl_element_t ui_display_token_blue[] = { - UI_BLUE_BACKGROUND("PUBLIC KEY EXPORT"), - - UI_BLUE_TEXT(0, - 30, - 185, - 260, - "Check if the following token is", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 30, - 201, - 260, - "identical on both devices:", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0x10, - 30, - 240, - 260, - G_io_apdu_buffer + 200, - BAGL_FONT_OPEN_SANS_LIGHT_16_22PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", - "CONFIRM", - io_seproxyhal_touch_display_token_cancel, - io_seproxyhal_touch_display_token_ok)}; - -const bagl_element_t ui_request_pubkey_approval_blue[] = { - UI_BLUE_BACKGROUND("PUBLIC KEY EXPORT"), - - UI_BLUE_TEXT(0, - 0, - 160, - 320, - "Approve to export your public keys", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", - "CONFIRM", - io_seproxyhal_touch_display_cancel, - io_seproxyhal_touch_display_ok)}; - -const bagl_element_t ui_request_change_path_approval_blue[] = { - UI_BLUE_BACKGROUND("WARNING"), - - UI_BLUE_ICON(0x40, 135, 95, 50, 50, &C_blue_badge_warning, COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 185, - 320, - "The change path is unusual.", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 203, - 320, - "Reject if you're not sure.", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 220, - 320, - "Contact Ledger support for help.", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 271, - 320, - "Change path:", - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 297, - 320, - vars.tmp_warning.derivation_path, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 314, - 320, - vars.tmp_warning.derivation_path + 30, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 331, - 320, - vars.tmp_warning.derivation_path + 60, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - UI_BLUE_TEXT(0, - 0, - 348, - 320, - vars.tmp_warning.derivation_path + 90, - BAGL_FONT_OPEN_SANS_SEMIBOLD_11_16PX, - BAGL_FONT_ALIGNMENT_CENTER, - COLOR_BLACK, - COLOR_BG_1), - - UI_BLUE_BUTTONS_REJECT_OR_CONFIRM("REJECT", - "CONFIRM", - io_seproxyhal_touch_display_cancel, - io_seproxyhal_touch_display_ok)}; - -unsigned int ui_display_address_blue_prepro(const bagl_element_t *element) { - bagl_icon_details_t *icon_details = &vars.tmpqr.icon_details; - bagl_element_t *icon_component = element; - copy_element_and_map_coin_colors(element); - if (element->component.userid > 0) { - unsigned int length = strlen(G_io_apdu_buffer + 200); - switch (element->component.userid) { - // qrcode, need magnifying - case 0x02: { - unsigned int x, y, x_off, y_off, bit; -#define PIXEL_SIZE 5 - os_memmove(&tmp_element, element, sizeof(bagl_element_t)); - tmp_element.component.width = PIXEL_SIZE; - tmp_element.component.height = PIXEL_SIZE; - x_off = 320 / 2 - vars.tmpqr.qrcode[0] * PIXEL_SIZE / 2; - y_off = 139 + (414 - 139) / 2 - vars.tmpqr.qrcode[0] * PIXEL_SIZE / 2; - bit = 0; - - y = 0; - x = 0; - tmp_element.component.fgcolor = - vars.tmpqr.qrcode[1 + (bit >> 3)] & (1 << (bit & 0x7)) ? COLOR_BLACK - : COLOR_WHITE; - tmp_element.component.x = x_off + x * PIXEL_SIZE; - tmp_element.component.y = y_off + y * PIXEL_SIZE; - bit++; - x = 1; - goto send_and_next; - - for (y = 0; y < vars.tmpqr.qrcode[0]; y++) { - for (x = 0; x < vars.tmpqr.qrcode[0]; x++) { - send_and_next: - io_seproxyhal_display(&tmp_element); - // tmp_element.component.fgcolor = - // vars.tmpqr.qrcode[1+((y*0x1D+x)>>3)]&(1<<((y*0x1D+x)&0x7)) - // ? COLOR_BLACK: COLOR_WHITE; - tmp_element.component.fgcolor = - vars.tmpqr.qrcode[1 + (bit >> 3)] & (1 << (bit & 0x7)) ? COLOR_BLACK - : COLOR_WHITE; - tmp_element.component.x = x_off + x * PIXEL_SIZE; - tmp_element.component.y = y_off + y * PIXEL_SIZE; - bit++; - io_seproxyhal_spi_recv(G_io_seproxyhal_spi_buffer, - sizeof(G_io_seproxyhal_spi_buffer), - 0); - } - } - // don't use the common draw method, we've already drawn the - // component - return 0; - } - - // address lines - case 0x10: - case 0x11: - default: - if (length >= (element->component.userid & 0xF) * MAX_CHAR_PER_LINE) { - os_memset(vars.tmpqr.addressSummary, 0, MAX_CHAR_PER_LINE + 1); - os_memmove(vars.tmpqr.addressSummary, - G_io_apdu_buffer + 200 + - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, - MIN(length - (element->component.userid & 0xF) * MAX_CHAR_PER_LINE, - MAX_CHAR_PER_LINE)); - return &tmp_element; - } - break; - } - // nothing to draw for this line - return 0; - } - return &tmp_element; -} - -unsigned int ui_display_token_blue_prepro(const bagl_element_t *element) { - copy_element_and_map_coin_colors(element); - return element; -} - -unsigned int ui_request_pubkey_approval_blue_prepro(const bagl_element_t *element) { - copy_element_and_map_coin_colors(element); - return element; -} - -unsigned int ui_request_change_path_approval_blue_prepro(const bagl_element_t *element) { - copy_element_and_map_coin_colors(element); - return element; -} - -unsigned int ui_display_derivation_warning_button(unsigned int button_mask, - unsigned int button_mask_counter) { - return 0; -} - -unsigned int ui_display_address_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) { - return 0; -} - -unsigned int ui_display_token_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) { - return 0; -} -unsigned int ui_request_pubkey_approval_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) { - return 0; -} - -unsigned int ui_request_change_path_approval_blue_button(unsigned int button_mask, - unsigned int button_mask_counter) { - return 0; -} - -#endif // #if defined(TARGET_BLUE) - #if defined(TARGET_NANOS) const bagl_element_t ui_display_address_nanos[] = { @@ -1809,27 +454,6 @@ unsigned int ui_verify_message_prepro(const bagl_element_t *element) { } #endif // #if defined(TARGET_NANOS) - -#ifdef TARGET_BLUE - -unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e) { - UX_DISPLAY(ui_settings_blue, ui_settings_blue_prepro); - return 0; // do not redraw button, screen has switched -} - -unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e) { - // go back to the home screen - os_sched_exit(0); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_display_address_blue(const bagl_element_t *e) { - load_qr_code(G_io_apdu_buffer + 200); - UX_DISPLAY(ui_display_address_blue, ui_display_address_blue_prepro); - return 0; -} -#endif // TARGET_BLUE - unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { // user denied the transaction, tell the USB side if (!btchip_bagl_user_action(0)) { @@ -2050,69 +674,6 @@ unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_ma #endif // #if defined(TARGET_NANOS) -#if defined(TARGET_BLUE) -void ui_transaction_blue_init(void) { - UX_DISPLAY(ui_transaction_blue, ui_transaction_blue_prepro); -} - -void ui_transaction_full_blue_init(void) { - ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; - G_ui_transaction_blue_state = TRANSACTION_FULL; - ui_transaction_blue_values[0] = vars.tmp.fullAmount; - ui_transaction_blue_values[1] = vars.tmp.fullAddress; - ui_transaction_blue_values[2] = vars.tmp.feesAmount; - ui_transaction_blue_init(); -} - -void ui_transaction_output_blue_init(void) { - ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; - G_ui_transaction_blue_state = TRANSACTION_OUTPUT; - snprintf(vars.tmp.output_numbering, - sizeof(vars.tmp.output_numbering), - "%d / %d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1, - btchip_context_D.totalOutputs); - ui_transaction_blue_values[0] = vars.tmp.output_numbering; - ui_transaction_blue_values[1] = vars.tmp.fullAddress; - ui_transaction_blue_values[2] = vars.tmp.fullAmount; - ui_transaction_blue_init(); -} - -void ui_transaction_finalize_blue_init(void) { - ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; - G_ui_transaction_blue_state = TRANSACTION_FINALIZE; - ui_transaction_blue_values[0] = vars.tmp.fullAmount; - ui_transaction_blue_values[1] = vars.tmp.feesAmount; - ui_transaction_blue_values[2] = NULL; - ui_transaction_blue_init(); -} - -void ui_message_signature_blue_init(void) { - ui_transaction_blue_ok = - (bagl_element_callback_t) io_seproxyhal_touch_message_signature_verify_ok; - ui_transaction_blue_cancel = - (bagl_element_callback_t) io_seproxyhal_touch_message_signature_verify_cancel; - G_ui_transaction_blue_state = TRANSACTION_MESSAGE; - ui_transaction_blue_values[0] = vars.tmp.fullAddress; - ui_transaction_blue_values[1] = NULL; - ui_transaction_blue_values[2] = NULL; - ui_transaction_blue_init(); -} - -void ui_transaction_p2sh_blue_init(void) { - ui_transaction_blue_ok = (bagl_element_callback_t) io_seproxyhal_touch_verify_ok; - ui_transaction_blue_cancel = (bagl_element_callback_t) io_seproxyhal_touch_verify_cancel; - G_ui_transaction_blue_state = TRANSACTION_P2SH; - ui_transaction_blue_values[0] = NULL; - ui_transaction_blue_values[1] = NULL; - ui_transaction_blue_values[2] = NULL; - ui_transaction_blue_init(); -} -#endif // #if defined(TARGET_BLUE) - #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) const char *settings_submenu_getter(unsigned int idx); @@ -2513,8 +1074,6 @@ void ui_idle(void) { ux_step_count = 0; ux_loop_over_curr_element = 0; -#if defined(TARGET_BLUE) - UX_DISPLAY(ui_idle_blue, ui_idle_blue_prepro); #elif defined(TARGET_NANOS) UX_MENU_DISPLAY(0, menu_main, NULL); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) @@ -2948,9 +1507,7 @@ unsigned int btchip_bagl_confirm_full_output() { return 0; } -#if defined(TARGET_BLUE) - ui_transaction_full_blue_init(); -#elif defined(TARGET_NANOS) +#if defined(TARGET_NANOS) ux_step = 0; ux_step_count = 4; UX_DISPLAY(ui_verify_nanos, ui_verify_prepro); @@ -2962,13 +1519,6 @@ unsigned int btchip_bagl_confirm_full_output() { unsigned int btchip_bagl_confirm_single_output() { // TODO : remove when supporting multi output -#if defined(TARGET_BLUE) - if (btchip_context_D.transactionContext.consumeP2SH) { - ui_transaction_p2sh_blue_init(); - return 1; - } -#endif - if (!prepare_single_output()) { return 0; } @@ -2978,9 +1528,7 @@ unsigned int btchip_bagl_confirm_single_output() { "output #%d", btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1); -#if defined(TARGET_BLUE) - ui_transaction_output_blue_init(); -#elif defined(TARGET_NANOS) +#if defined(TARGET_NANOS) ux_step = 0; ux_step_count = 3; UX_DISPLAY(ui_verify_output_nanos, ui_verify_output_prepro); @@ -2995,9 +1543,7 @@ unsigned int btchip_bagl_finalize_tx() { return 0; } -#if defined(TARGET_BLUE) - ui_transaction_finalize_blue_init(); -#elif defined(TARGET_NANOS) +#if defined(TARGET_NANOS) ux_step = 0; ux_step_count = 2; UX_DISPLAY(ui_finalize_nanos, ui_finalize_prepro); @@ -3012,9 +1558,7 @@ void btchip_bagl_confirm_message_signature() { return; } -#if defined(TARGET_BLUE) - ui_message_signature_blue_init(); -#elif defined(TARGET_NANOS) +#if defined(TARGET_NANOS) ux_step = 0; ux_step_count = 2; UX_DISPLAY(ui_verify_message_signature_nanos, ui_verify_message_prepro); @@ -3032,16 +1576,7 @@ void btchip_bagl_display_public_key(unsigned char *derivation_path) { MAX_DERIV_PATH_ASCII_LENGTH); uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); -#if defined(TARGET_BLUE) - - if (is_derivation_path_unusual) { - UX_DISPLAY(ui_display_derivation_warning, ui_request_change_path_approval_blue_prepro); - } else { - load_qr_code(G_io_apdu_buffer + 200); - UX_DISPLAY(ui_display_address_blue, ui_display_address_blue_prepro); - } - -#elif defined(TARGET_NANOS) +#if defined(TARGET_NANOS) // prepend a white space to the address G_io_apdu_buffer[199] = ' '; ux_step = is_derivation_path_unusual ? 0 : 4; @@ -3056,10 +1591,9 @@ void btchip_bagl_display_public_key(unsigned char *derivation_path) { #endif // TARGET_NANOX } -void btchip_bagl_display_token() { -#if defined(TARGET_BLUE) - UX_DISPLAY(ui_display_token_blue, ui_display_token_blue_prepro); -#elif defined(TARGET_NANOS) +void btchip_bagl_display_token() +{ +#if defined(TARGET_NANOS) ux_step = 0; ux_step_count = 1; UX_DISPLAY(ui_display_token_nanos, NULL); @@ -3068,10 +1602,9 @@ void btchip_bagl_display_token() { #endif // #if TARGET_ID } -void btchip_bagl_request_pubkey_approval() { -#if defined(TARGET_BLUE) - UX_DISPLAY(ui_request_pubkey_approval_blue, ui_request_pubkey_approval_blue_prepro); -#elif defined(TARGET_NANOS) +void btchip_bagl_request_pubkey_approval() +{ +#if defined(TARGET_NANOS) // append and prepend a white space to the address ux_step = 0; ux_step_count = 1; @@ -3083,9 +1616,7 @@ void btchip_bagl_request_pubkey_approval() { void btchip_bagl_request_change_path_approval(unsigned char *change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); -#if defined(TARGET_BLUE) - UX_DISPLAY(ui_request_change_path_approval_blue, ui_request_change_path_approval_blue_prepro); -#elif defined(TARGET_NANOS) +#if defined(TARGET_NANOS) // append and prepend a white space to the address ux_step = 0; ux_step_count = 4; @@ -3112,11 +1643,6 @@ btchip_altcoin_config_t const C_coin_config = { .p2sh_version = COIN_P2SH_VERSION, .family = COIN_FAMILY, // unsigned char* iconsuffix;// will use the icon provided on the stack (maybe) -#ifdef TARGET_BLUE - .header_text = COIN_COINID_HEADER, - .color_header = COIN_COLOR_HDR, - .color_dashboard = COIN_COLOR_DB, -#endif // TARGET_BLUE .coinid = COIN_COINID, .name = COIN_COINID_NAME, .name_short = COIN_COINID_SHORT, @@ -3141,18 +1667,9 @@ __attribute__((section(".boot"))) int main(int arg0) { strcpy(name, COIN_COINID_NAME); unsigned char name_short[sizeof(COIN_COINID_SHORT)]; strcpy(name_short, COIN_COINID_SHORT); -#ifdef TARGET_BLUE - unsigned char header[sizeof(COIN_COINID_HEADER)]; - strcpy(header, COIN_COINID_HEADER); -#endif // TARGET_BLUE btchip_altcoin_config_t coin_config; os_memmove(&coin_config, &C_coin_config, sizeof(coin_config)); -#ifdef TARGET_BLUE - coin_config.header_text = header; - coin_config.color_header = COIN_COLOR_HDR; - coin_config.color_dashboard = COIN_COLOR_DB; -#endif // TARGET_BLUE coin_config.coinid = coinid; coin_config.name = name; coin_config.name_short = name_short; @@ -3215,12 +1732,6 @@ __attribute__((section(".boot"))) int main(int arg0) { BLE_power(1, "Nano X"); #endif // HAVE_BLE -#if defined(TARGET_BLUE) - // setup the status bar colors (remembered after wards, even - // more if another app does not resetup after app switch) - UX_SET_STATUS_BAR_COLOR(COLOR_WHITE, G_coin_config->color_header); -#endif // TARGET_ID - app_main(); } CATCH(EXCEPTION_IO_RESET) { From 0c3c41b0d5eafa7602b221b84ceb3ded133b328a Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 22 Nov 2022 16:48:30 +0100 Subject: [PATCH 04/41] Add conditional compilation for Stax compatiblity. --- src/main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index c8d8a89..b663307 100644 --- a/src/main.c +++ b/src/main.c @@ -30,7 +30,9 @@ #define __NAME3(a, b, c) a##b##c #define NAME3(a, b, c) __NAME3(a, b, c) +#ifndef TARGET_FATSTACKS bagl_element_t tmp_element; +#endif unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; @@ -123,6 +125,7 @@ union { */ } vars; +#ifndef TARGET_FATSTACKS unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e); @@ -133,6 +136,7 @@ unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e); unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e); +#endif void ui_idle(void); #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) @@ -148,11 +152,13 @@ unsigned int ux_step; unsigned int ux_step_count; uint8_t ux_loop_over_curr_element; // Nano S only +#ifndef TARGET_FATSTACKS const bagl_element_t *ui_menu_item_out_over(const bagl_element_t *e) { // the selection rectangle is after the none|touchable e = (const bagl_element_t *) (((unsigned int) e) + sizeof(bagl_element_t)); return e; } +#endif #if defined(TARGET_NANOS) @@ -453,7 +459,8 @@ unsigned int ui_verify_message_prepro(const bagl_element_t *element) { return 1; } -#endif // #if defined(TARGET_NANOS) +#endif // #if defined(TARGET_NANOS) +#ifndef TARGET_FATSTACKS unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { // user denied the transaction, tell the USB side if (!btchip_bagl_user_action(0)) { @@ -523,6 +530,7 @@ unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e) { ui_idle(); return 0; // DO NOT REDRAW THE BUTTON } +#endif #if defined(TARGET_NANOS) unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { @@ -1085,12 +1093,14 @@ void ui_idle(void) { #endif // #if TARGET_ID } +#ifndef TARGET_FATSTACKS // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { io_seproxyhal_display_default((bagl_element_t *) element); } } +#endif unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { switch (channel & ~(IO_FLAGS)) { From 9b0ad01d4f8809dcf1cb2037df0510c7dc95f703 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 22 Nov 2022 16:49:41 +0100 Subject: [PATCH 05/41] Move BAGL main menu UX code to separate file. --- src/main.c | 98 +++++--------------- src/ui/ui_main_menu.h | 19 ++++ src/ui/ui_main_menu_bagl.c | 183 +++++++++++++++++++++++++++++++++++++ src/ui/ui_shared.c | 21 +++++ src/ui/ui_shared.h | 26 ++++++ 5 files changed, 272 insertions(+), 75 deletions(-) create mode 100644 src/ui/ui_main_menu.h create mode 100644 src/ui/ui_main_menu_bagl.c create mode 100644 src/ui/ui_shared.c create mode 100644 src/ui/ui_shared.h diff --git a/src/main.c b/src/main.c index b663307..b5a307e 100644 --- a/src/main.c +++ b/src/main.c @@ -27,6 +27,9 @@ #include "ux.h" +#include "ui_main_menu.h" +#include "ui_shared.h" + #define __NAME3(a, b, c) a##b##c #define NAME3(a, b, c) __NAME3(a, b, c) @@ -684,68 +687,6 @@ unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_ma #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) -const char *settings_submenu_getter(unsigned int idx); -void settings_submenu_selector(unsigned int idx); - -void settings_pubkey_export_change(unsigned int enabled) { - nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &enabled, 1); - ui_idle(); -} -////////////////////////////////////////////////////////////////////////////////////// -// Public keys export submenu: - -const char *const settings_pubkey_export_getter_values[] = {"Auto Approval", - "Manual Approval", - "Back"}; - -const char *settings_pubkey_export_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { - return settings_pubkey_export_getter_values[idx]; - } - return NULL; -} - -void settings_pubkey_export_selector(unsigned int idx) { - switch (idx) { - case 0: - settings_pubkey_export_change(0); - break; - case 1: - settings_pubkey_export_change(1); - break; - default: - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); - } -} - -////////////////////////////////////////////////////////////////////////////////////// -// Settings menu: - -const char *const settings_submenu_getter_values[] = { - "Public keys export", - "Back", -}; - -const char *settings_submenu_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_submenu_getter_values)) { - return settings_submenu_getter_values[idx]; - } - return NULL; -} - -void settings_submenu_selector(unsigned int idx) { - switch (idx) { - case 0: - ux_menulist_init_select(0, - settings_pubkey_export_getter, - settings_pubkey_export_selector, - N_btchip.pubKeyRequestRestriction); - break; - default: - ui_idle(); - } -} - ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_idle_flow_1_step, nn, @@ -1137,20 +1078,27 @@ unsigned char io_event(unsigned char channel) { UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); break; - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; +#ifndef TARGET_FATSTACKS + case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: + UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); + break; +#endif - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - // no break is intentional - default: - UX_DEFAULT_EVENT(); - break; + case SEPROXYHAL_TAG_STATUS_EVENT: + if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && + !(U4BE(G_io_seproxyhal_spi_buffer, 3) & + SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { + THROW(EXCEPTION_IO_RESET); + } + // no break is intentional + default: + UX_DEFAULT_EVENT(); + break; +#ifndef TARGET_FATSTACKS + case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: + UX_DISPLAYED_EVENT({}); + break; +#endif case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: UX_DISPLAYED_EVENT({}); diff --git a/src/ui/ui_main_menu.h b/src/ui/ui_main_menu.h new file mode 100644 index 0000000..1cbd819 --- /dev/null +++ b/src/ui/ui_main_menu.h @@ -0,0 +1,19 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#pragma once + +void ui_idle(void); diff --git a/src/ui/ui_main_menu_bagl.c b/src/ui/ui_main_menu_bagl.c new file mode 100644 index 0000000..ee9cb2d --- /dev/null +++ b/src/ui/ui_main_menu_bagl.c @@ -0,0 +1,183 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#ifdef HAVE_BAGL +#include "ui_main_menu.h" +#include "ui_shared.h" +#include "os.h" +#include "os_io_seproxyhal.h" +#include "ux.h" +#include "string.h" + +#include "btchip_internal.h" + +// #include "btchip_bagl_extensions.h" + +#if defined(TARGET_NANOS) + +const ux_menu_entry_t menu_main[]; +const ux_menu_entry_t menu_settings[]; + +// change the setting +void menu_settings_pubKeyRequestRestriction_change(unsigned int enabled) { + nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); + // go back to the menu entry + UX_MENU_DISPLAY(0, menu_main, NULL); +} +const ux_menu_entry_t menu_settings_pubKeyRequestRestriction[] = { + {NULL, menu_settings_pubKeyRequestRestriction_change, 1, NULL, "Manual approval", NULL, 0, 0}, + {NULL, menu_settings_pubKeyRequestRestriction_change, 0, NULL, "Auto approval", NULL, 0, 0}, + UX_MENU_END +}; +const ux_menu_entry_t menu_settings[] = { + {menu_settings_pubKeyRequestRestriction, NULL, 0, NULL, "Public keys", "export approval", 0, 0}, + {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, + UX_MENU_END}; + +const ux_menu_entry_t menu_about[] = { + {NULL, NULL, 0, NULL, "Version", APPVERSION, 0, 0}, + {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, + UX_MENU_END}; + +const ux_menu_entry_t menu_main[] = { + //{NULL, NULL, 0, &NAME3(C_nanos_badge_, COINID, ), "Use wallet to", "view + //accounts", 33, 12}, + {NULL, NULL, 0, NULL, "Use wallet to", "view accounts", 0, 0}, + {menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0}, + {menu_about, NULL, 0, NULL, "About", NULL, 0, 0}, + {NULL, os_sched_exit, 0, &C_nanos_icon_dashboard, "Quit app", NULL, 50, 29}, + UX_MENU_END}; + +#endif // #if defined(TARGET_NANOS) + +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) + +const char* settings_submenu_getter(unsigned int idx); +void settings_submenu_selector(unsigned int idx); + + +void settings_pubkey_export_change(unsigned int enabled) { + nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); + ui_idle(); +} +////////////////////////////////////////////////////////////////////////////////////// +// Public keys export submenu: + +const char* const settings_pubkey_export_getter_values[] = { + "Auto Approval", + "Manual Approval", + "Back" +}; + +const char* settings_pubkey_export_getter(unsigned int idx) { + if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { + return settings_pubkey_export_getter_values[idx]; + } + return NULL; +} + +void settings_pubkey_export_selector(unsigned int idx) { + switch(idx) { + case 0: + settings_pubkey_export_change(0); + break; + case 1: + settings_pubkey_export_change(1); + break; + default: + ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); + } +} + +////////////////////////////////////////////////////////////////////////////////////// +// Settings menu: + +const char* const settings_submenu_getter_values[] = { + "Public keys export", + "Back", +}; + +const char* settings_submenu_getter(unsigned int idx) { + if (idx < ARRAYLEN(settings_submenu_getter_values)) { + return settings_submenu_getter_values[idx]; + } + return NULL; +} + +void settings_submenu_selector(unsigned int idx) { + switch(idx) { + case 0: + ux_menulist_init_select(0, settings_pubkey_export_getter, settings_pubkey_export_selector, N_btchip.pubKeyRequestRestriction); + break; + default: + ui_idle(); + } +} + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB( + ux_idle_flow_1_step, + nn, + { + "Application", + "is ready", + }); +UX_STEP_VALID( + ux_idle_flow_2_step, + pb, + ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector), + { + &C_icon_coggle, + "Settings", + }); +UX_STEP_NOCB( + ux_idle_flow_3_step, + bn, + { + "Version", + APPVERSION, + }); +UX_STEP_VALID( + ux_idle_flow_4_step, + pb, + os_sched_exit(-1), + { + &C_icon_dashboard_x, + "Quit", + }); +UX_FLOW(ux_idle_flow, + &ux_idle_flow_1_step, + &ux_idle_flow_2_step, + &ux_idle_flow_3_step, + &ux_idle_flow_4_step +); +#endif + +void ui_idle(void) { + ux_step_count = 0; + ux_loop_over_curr_element = 0; + +#if defined(TARGET_NANOS) + UX_MENU_DISPLAY(0, menu_main, NULL); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + // reserve a display stack slot if none yet + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_idle_flow, NULL); +#endif // #if TARGET_ID +} +#endif // HAVE_BAGL diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c new file mode 100644 index 0000000..60c4308 --- /dev/null +++ b/src/ui/ui_shared.c @@ -0,0 +1,21 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#include "ui_shared.h" + +unsigned int ux_step; +unsigned int ux_step_count; +uint8_t ux_loop_over_curr_element; diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h new file mode 100644 index 0000000..16973dc --- /dev/null +++ b/src/ui/ui_shared.h @@ -0,0 +1,26 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ + +#pragma once + +#include + +extern unsigned int ux_step; +extern unsigned int ux_step_count; +extern uint8_t ux_loop_over_curr_element; + +// unsigned int io_seproxyhal_touch_tx_ok(const void *e); From 4f7bff619e7967d306e9a0d6bc354bcf29c45b46 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 22 Nov 2022 18:16:55 +0100 Subject: [PATCH 06/41] Add Stax main menu UX. --- src/ui/ui_main_menu_nbgl.c | 95 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/ui/ui_main_menu_nbgl.c diff --git a/src/ui/ui_main_menu_nbgl.c b/src/ui/ui_main_menu_nbgl.c new file mode 100644 index 0000000..df12bcc --- /dev/null +++ b/src/ui/ui_main_menu_nbgl.c @@ -0,0 +1,95 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#ifdef HAVE_NBGL +#include "ui_main_menu.h" +#include "ui_shared.h" +#include "os.h" +#include "os_io_seproxyhal.h" +#include "ux.h" +#include "string.h" + +#include "glyphs.h" +#include "nbgl_page.h" +#include "nbgl_use_case.h" + +#include "btchip_internal.h" + +static void displaySettingsMenu(void); +static void settingsControlsCallback(int token, uint8_t index); +static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content); + +#define SWITCH_KEY_EXPORT_TOKEN FIRST_USER_TOKEN + +#define NB_INFO_FIELDS 2 +static const char* const infoTypes[] = {"Version", "Decred App"}; +static const char* const infoContents[] = {APPVERSION, "(c) 2022 Ledger"}; + +static nbgl_layoutSwitch_t setting_switch; + +void onQuitCallback(void) +{ + os_sched_exit(-1); +} + +static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content) { + if (page == 0) { + setting_switch.text = "Public keys export"; + setting_switch.subText = "Enable automatic key export"; + setting_switch.token = SWITCH_KEY_EXPORT_TOKEN; + setting_switch.tuneId = TUNE_TAP_CASUAL; + + content->type = SWITCHES_LIST; + content->switchesList.nbSwitches = 1; + content->switchesList.switches = (nbgl_layoutSwitch_t*) &setting_switch; + } + else if (page == 1) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char**) infoTypes; + content->infosList.infoContents = (const char**) infoContents; + } + else { + return false; + } + return true; +} + +static void settingsControlsCallback(int token, uint8_t index) { + UNUSED(index); + switch(token) + { + case SWITCH_KEY_EXPORT_TOKEN: + setting_switch.initState = !setting_switch.initState; + unsigned int setting_value = (unsigned int) !setting_switch.initState; + nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &setting_value, 1); + displaySettingsMenu(); + break; + default: + PRINTF("Should not happen !"); + break; + } +} + +static void displaySettingsMenu(void) { + nbgl_useCaseSettings("Stellar settings",0,2,true,ui_idle,settingsNavCallback,settingsControlsCallback); +} + +void ui_idle(void) { + setting_switch.initState = (bool) ! N_btchip.pubKeyRequestRestriction; + nbgl_useCaseHome("Decred", NULL/*&C_icon_stellar_64px*/, "This app confirms actions on\nthe Decred network.", true, displaySettingsMenu, onQuitCallback); +} +#endif // HAVE_NBGL From c2c7c9e2507337730da8112eb458769ed91d963a Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 24 Nov 2022 14:26:11 +0100 Subject: [PATCH 07/41] Move UX main menu files to specific directory. --- src/ui/{ => main}/ui_main_menu.h | 0 src/ui/{ => main}/ui_main_menu_bagl.c | 0 src/ui/{ => main}/ui_main_menu_nbgl.c | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/ui/{ => main}/ui_main_menu.h (100%) rename src/ui/{ => main}/ui_main_menu_bagl.c (100%) rename src/ui/{ => main}/ui_main_menu_nbgl.c (100%) diff --git a/src/ui/ui_main_menu.h b/src/ui/main/ui_main_menu.h similarity index 100% rename from src/ui/ui_main_menu.h rename to src/ui/main/ui_main_menu.h diff --git a/src/ui/ui_main_menu_bagl.c b/src/ui/main/ui_main_menu_bagl.c similarity index 100% rename from src/ui/ui_main_menu_bagl.c rename to src/ui/main/ui_main_menu_bagl.c diff --git a/src/ui/ui_main_menu_nbgl.c b/src/ui/main/ui_main_menu_nbgl.c similarity index 100% rename from src/ui/ui_main_menu_nbgl.c rename to src/ui/main/ui_main_menu_nbgl.c From 938971773fe1c1ecde0b2fdc2ed361053c5b9f78 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 24 Nov 2022 14:28:35 +0100 Subject: [PATCH 08/41] Move public key BAGL UX functions to specific file. --- src/btchip_apdu_get_wallet_public_key.c | 1 + src/btchip_bagl_extensions.h | 37 +- src/main.c | 1408 ++++++++--------------- src/ui/pubkey/ui_pubkey.h | 21 + src/ui/pubkey/ui_pubkey_bagl.c | 364 ++++++ src/ui/ui_shared.c | 1 + src/ui/ui_shared.h | 37 + 7 files changed, 950 insertions(+), 919 deletions(-) create mode 100644 src/ui/pubkey/ui_pubkey.h create mode 100644 src/ui/pubkey/ui_pubkey_bagl.c diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index bafa5cf..0505419 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -19,6 +19,7 @@ #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" +#include "ui_pubkey.h" #define P1_NO_DISPLAY 0x00 #define P1_DISPLAY 0x01 diff --git a/src/btchip_bagl_extensions.h b/src/btchip_bagl_extensions.h index 11e53d0..11029b4 100644 --- a/src/btchip_bagl_extensions.h +++ b/src/btchip_bagl_extensions.h @@ -1,19 +1,19 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #ifndef _BTCHIP_BAGL_H_ #define _BTCHIP_BAGL_H_ @@ -33,20 +33,13 @@ unsigned int btchip_bagl_finalize_tx(void); // UI response to btchip to finish the exchange unsigned char btchip_bagl_user_action(unsigned char confirming); -// request the UI to redisplay the idle screen -void btchip_bagl_idle(void); - // btchip asking message signing confirmation void btchip_bagl_confirm_message_signature(void); // UI response to message signature void btchip_bagl_user_action_message_signing(unsigned char confirming); -// Public key display -void btchip_bagl_display_public_key(unsigned char* derivation_path); void btchip_bagl_user_action_display(unsigned char confirming); - -void btchip_bagl_request_pubkey_approval(void); void btchip_bagl_request_change_path_approval(unsigned char* change_path); #endif /* _BTCHIP_BAGL_H_ */ diff --git a/src/main.c b/src/main.c index b5a307e..7768fa4 100644 --- a/src/main.c +++ b/src/main.c @@ -1,19 +1,19 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "os.h" #include "cx.h" @@ -28,10 +28,11 @@ #include "ux.h" #include "ui_main_menu.h" +#include "ui_pubkey.h" #include "ui_shared.h" #define __NAME3(a, b, c) a##b##c -#define NAME3(a, b, c) __NAME3(a, b, c) +#define NAME3(a, b, c) __NAME3(a, b, c) #ifndef TARGET_FATSTACKS bagl_element_t tmp_element; @@ -39,100 +40,25 @@ bagl_element_t tmp_element; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10 +#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10 #define BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH 8 -#define MAX_CHAR_PER_LINE 25 - -#define COLOR_BG_1 0xF9F9F9 -#define COLOR_APP COIN_COLOR_HDR // bitcoin 0xFCB653 -#define COLOR_APP_LIGHT COIN_COLOR_DB // bitcoin 0xFEDBA9 -#define COLOR_BLACK 0x000000 -#define COLOR_WHITE 0xFFFFFF -#define COLOR_GRAY 0x999999 -#define COLOR_LIGHT_GRAY 0xEEEEEE +#define MAX_CHAR_PER_LINE 25 -#define UI_NANOS_BACKGROUND() \ - { \ - {BAGL_RECTANGLE, 0, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0, COLOR_WHITE, 0, 0}, NULL, 0, 0, 0, \ - NULL, NULL, NULL \ - } -#define UI_NANOS_ICON_LEFT(userid, glyph) \ - { \ - {BAGL_ICON, userid, 3, 12, 7, 7, 0, 0, 0, COLOR_WHITE, 0, 0, glyph}, NULL, 0, 0, 0, NULL, \ - NULL, NULL \ - } -#define UI_NANOS_ICON_RIGHT(userid, glyph) \ - { \ - {BAGL_ICON, userid, 117, 13, 8, 6, 0, 0, 0, COLOR_WHITE, 0, 0, glyph}, NULL, 0, 0, 0, \ - NULL, NULL, NULL \ - } -#define UI_NANOS_TEXT(userid, x, y, w, text, font) \ - { \ - {BAGL_LABELINE, \ - userid, \ - x, \ - y, \ - w, \ - 12, \ - 0, \ - 0, \ - 0, \ - COLOR_WHITE, \ - 0, \ - font | BAGL_FONT_ALIGNMENT_CENTER, \ - 0}, \ - (char *) text, 0, 0, 0, NULL, NULL, NULL \ - } -// Only one scrolling text per screen can be displayed -#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) \ - { \ - {BAGL_LABELINE, \ - userid, \ - x, \ - y, \ - w, \ - 12, \ - 0x80 | 10, \ - 0, \ - 0, \ - COLOR_WHITE, \ - 0, \ - font | BAGL_FONT_ALIGNMENT_CENTER, \ - 26}, \ - (char *) text, 0, 0, 0, NULL, NULL, NULL \ - } +#define COLOR_BG_1 0xF9F9F9 +#define COLOR_APP COIN_COLOR_HDR // bitcoin 0xFCB653 +#define COLOR_APP_LIGHT COIN_COLOR_DB // bitcoin 0xFEDBA9 +#define COLOR_BLACK 0x000000 -union { - struct { - // char addressSummary[40]; // beginning of the output address ... end - // of - - char fullAddress[43]; // the address - char fullAmount[20]; // full amount - char feesAmount[20]; // fees - } tmp; - - struct { - char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; - } tmp_warning; - - /* - struct { - bagl_icon_details_t icon_details; - unsigned int colors[2]; - unsigned char qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(3)]; - } tmpqr; - - unsigned int dummy; // ensure the whole vars is aligned for the CM0 to - operate correctly - */ -} vars; +#define COLOR_GRAY 0x999999 +#define COLOR_LIGHT_GRAY 0xEEEEEE #ifndef TARGET_FATSTACKS unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e); +unsigned int +io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e); +unsigned int +io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e); @@ -142,85 +68,24 @@ unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e); #endif void ui_idle(void); -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_FATSTACKS) #include "ux.h" ux_state_t G_ux; bolos_ux_params_t G_ux_params; #else ux_state_t ux; -#endif // TARGET_NANOX || TARGET_NANOS2 - -// display stepped screens -unsigned int ux_step; -unsigned int ux_step_count; -uint8_t ux_loop_over_curr_element; // Nano S only +#endif // TARGET_NANOX || TARGET_NANOS2 #ifndef TARGET_FATSTACKS const bagl_element_t *ui_menu_item_out_over(const bagl_element_t *e) { // the selection rectangle is after the none|touchable - e = (const bagl_element_t *) (((unsigned int) e) + sizeof(bagl_element_t)); + e = (const bagl_element_t *)(((unsigned int)e) + sizeof(bagl_element_t)); return e; } #endif #if defined(TARGET_NANOS) -const bagl_element_t ui_display_address_nanos[] = { - - UI_NANOS_BACKGROUND(), - - /* Displayed when derivation path is unusual */ - - UI_NANOS_TEXT(1, 0, 22, 128, "Warning !", BAGL_FONT_OPEN_SANS_LIGHT_16px), - - UI_NANOS_TEXT(2, 0, 12, 128, "The derivation", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(2, 0, 26, 128, "path is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Derivation path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, - 15, - 26, - 98, - vars.tmp_warning.derivation_path, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - /* Always displayed */ - - UI_NANOS_ICON_LEFT(5, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(5, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(5, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(5, 0, 26, 128, "address", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(6, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - // Hax, avoid wasting space - UI_NANOS_SCROLLING_TEXT(0x86, - 15, - 26, - 98, - G_io_apdu_buffer + 199, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - -const bagl_element_t ui_display_token_nanos[] = { - - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm token", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, G_io_apdu_buffer + 200, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; -const bagl_element_t ui_request_pubkey_approval_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Export", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, "public key?", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - const bagl_element_t ui_request_change_path_approval_nanos[] = { UI_NANOS_BACKGROUND(), @@ -230,47 +95,13 @@ const bagl_element_t ui_request_change_path_approval_nanos[] = { UI_NANOS_TEXT(2, 0, 26, 128, "is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Change path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, - 15, - 26, - 98, - vars.tmp_warning.derivation_path, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - -unsigned int ui_display_address_nanos_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); - if (display) { - switch (element->component.userid) { - case 0x83: - ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - case 5: - UX_CALLBACK_SET_INTERVAL(2000); - ux_loop_over_curr_element = - 0; // allow next timer to increment ux_step when triggered - break; - case 0x86: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - // ugly ux tricks, loops around last 2 screens - ux_step -= 1; // loops back to previous element on next redraw - ux_loop_over_curr_element = 1; // when the timer will trigger, ux_step won't be - // incremented, only redraw - break; - } - } - return display; - } - return 1; -} + UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t *element) { if (element->component.userid > 0) { @@ -278,8 +109,8 @@ unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t * if (display) { if (element->component.userid & 0x80) { ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); } } return display; @@ -287,14 +118,8 @@ unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t * return 1; } -unsigned int ui_display_address_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); -unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); -unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + unsigned int button_mask_counter); const bagl_element_t ui_verify_nanos[] = { UI_NANOS_BACKGROUND(), @@ -307,18 +132,14 @@ const bagl_element_t ui_verify_nanos[] = { UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, - 23, - 26, - 82, - vars.tmp.fullAddress, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(4, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_REGULAR_11px), UI_NANOS_SCROLLING_TEXT(4, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) }; -unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); +unsigned int ui_verify_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); const bagl_element_t ui_verify_output_nanos[] = { @@ -332,12 +153,8 @@ const bagl_element_t ui_verify_output_nanos[] = { UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, - 23, - 26, - 82, - vars.tmp.fullAddress, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; + UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; unsigned int ui_verify_output_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); @@ -352,6 +169,7 @@ const bagl_element_t ui_finalize_nanos[] = { UI_NANOS_TEXT(2, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) + /* TODO {{BAGL_LABELINE , 0x02, 0, 12, 128, 12, 0, 0, 0 , COLOR_WHITE, COLOR_BLACK, @@ -363,7 +181,8 @@ const bagl_element_t ui_finalize_nanos[] = { vars.tmp.fullAmount, 0, 0, 0, NULL, NULL, NULL }, */ }; -unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); +unsigned int ui_finalize_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); // display or not according to step, and adjust delay unsigned int ui_verify_prepro(const bagl_element_t *element) { @@ -371,15 +190,15 @@ unsigned int ui_verify_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - case 4: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + case 4: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -392,14 +211,14 @@ unsigned int ui_verify_output_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -412,13 +231,13 @@ unsigned int ui_finalize_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -434,27 +253,24 @@ const bagl_element_t ui_verify_message_signature_nanos[] = { UI_NANOS_TEXT(1, 0, 26, 128, "message", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(2, 0, 12, 128, "Message hash", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, - 23, - 26, - 82, - vars.tmp.fullAddress, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; -unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; +unsigned int +ui_verify_message_signature_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); unsigned int ui_verify_message_prepro(const bagl_element_t *element) { if (element->component.userid > 0) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -470,7 +286,7 @@ unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { // redraw ui ui_idle(); } - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { @@ -479,23 +295,25 @@ unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { // redraw ui ui_idle(); } - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { +unsigned int +io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { // user denied the transaction, tell the USB side btchip_bagl_user_action_message_signing(0); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { +unsigned int +io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { // user accepted the transaction, tell the USB side btchip_bagl_user_action_message_signing(1); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { @@ -503,7 +321,7 @@ unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { btchip_bagl_user_action_display(0); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { @@ -511,7 +329,7 @@ unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { btchip_bagl_user_action_display(1); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e) { @@ -521,30 +339,31 @@ unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e) { btchip_bagl_user_action_display(0); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e) { + unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e) { // Set the valid token flag btchip_context_D.has_valid_token = true; // user approved the token, tell the USB side btchip_bagl_user_action_display(1); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } #endif #if defined(TARGET_NANOS) -unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { +unsigned int ui_verify_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } @@ -552,518 +371,355 @@ unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int butto unsigned int ui_verify_output_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } -unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { +unsigned int ui_finalize_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } -unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int +ui_verify_message_signature_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_message_signature_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_message_signature_verify_ok(NULL); - break; - } - return 0; -} + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_message_signature_verify_cancel(NULL); + break; -unsigned int ui_display_address_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - if (ux_step == 3) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - break; - } - } else if (ux_step >= 4) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } else { - if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { - // if we were looping over a single element, disable this loop and diffuse the redisplay - // timeout (used by scrolling text) - if (ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - } + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_message_signature_verify_ok(NULL); + break; } return 0; } -unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_token_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_token_ok(NULL); - break; - } - return 0; -} -unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - switch (button_mask) { + unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) +{ + if (ux_step == 3) + { + switch (button_mask) + { case BUTTON_EVT_RELEASED | BUTTON_LEFT: io_seproxyhal_touch_display_cancel(NULL); break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; } - return 0; -} - -unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - if (ux_step == 3) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } else { - if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { - // if we were looping over a single element, disable this loop and diffuse the redisplay - // timeout (used by scrolling text) - if (ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); + } + else + { + if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) + { + // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) + if(ux_loop_over_curr_element) { + ux_loop_over_curr_element = 0; + ux.callback_interval_ms = 0; + } + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); } } return 0; } -#endif // #if defined(TARGET_NANOS) +#endif // #if defined(TARGET_NANOS) #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_idle_flow_1_step, - nn, - { - "Application", - "is ready", - }); -UX_STEP_VALID(ux_idle_flow_2_step, - pb, - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector), - { - &C_icon_coggle, - "Settings", - }); -UX_STEP_NOCB(ux_idle_flow_3_step, - bn, - { - "Version", - APPVERSION, - }); -UX_STEP_VALID(ux_idle_flow_4_step, - pb, - os_sched_exit(-1), - { - &C_icon_dashboard_x, - "Quit", - }); -UX_FLOW(ux_idle_flow, - &ux_idle_flow_1_step, - &ux_idle_flow_2_step, - &ux_idle_flow_3_step, - &ux_idle_flow_4_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_sign_flow_1_step, - pnn, - { - &C_icon_certificate, - "Sign", - "message", - }); -UX_STEP_NOCB(ux_sign_flow_2_step, - bnnn_paging, - { - .title = "Message hash", - .text = vars.tmp.fullAddress, - }); -UX_STEP_VALID(ux_sign_flow_3_step, - pbb, - io_seproxyhal_touch_message_signature_verify_ok(NULL), - { - &C_icon_validate_14, - "Sign", - "message", - }); -UX_STEP_VALID(ux_sign_flow_4_step, - pbb, - io_seproxyhal_touch_message_signature_verify_cancel(NULL), - { - &C_icon_crossmark, - "Cancel", - "signature", - }); +UX_STEP_NOCB( + ux_sign_flow_1_step, + pnn, + { + &C_icon_certificate, + "Sign", + "message", + }); +UX_STEP_NOCB( + ux_sign_flow_2_step, + bnnn_paging, + { + .title = "Message hash", + .text = vars.tmp.fullAddress, + }); +UX_STEP_VALID( + ux_sign_flow_3_step, + pbb, + io_seproxyhal_touch_message_signature_verify_ok(NULL), + { + &C_icon_validate_14, + "Sign", + "message", + }); +UX_STEP_VALID( + ux_sign_flow_4_step, + pbb, + io_seproxyhal_touch_message_signature_verify_cancel(NULL), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); UX_FLOW(ux_sign_flow, - &ux_sign_flow_1_step, - &ux_sign_flow_2_step, - &ux_sign_flow_3_step, - &ux_sign_flow_4_step); + &ux_sign_flow_1_step, + &ux_sign_flow_2_step, + &ux_sign_flow_3_step, + &ux_sign_flow_4_step +); ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_confirm_full_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction", - }); -UX_STEP_NOCB(ux_confirm_full_flow_2_step, - bnnn_paging, - {.title = "Amount", .text = vars.tmp.fullAmount}); -UX_STEP_NOCB(ux_confirm_full_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB(ux_confirm_full_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID(ux_confirm_full_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send", - }); -UX_STEP_VALID(ux_confirm_full_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); + pnn, + { + &C_icon_eye, + "Review", + "transaction", + }); +UX_STEP_NOCB( + ux_confirm_full_flow_2_step, + bnnn_paging, + { + .title = "Amount", + .text = vars.tmp.fullAmount + }); +UX_STEP_NOCB( + ux_confirm_full_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB( + ux_confirm_full_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID( + ux_confirm_full_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + "and send", + }); +UX_STEP_VALID( + ux_confirm_full_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress / Fees: feesAmount UX_FLOW(ux_confirm_full_flow, - &ux_confirm_full_flow_1_step, - &ux_confirm_full_flow_2_step, - &ux_confirm_full_flow_3_step, - &ux_confirm_full_flow_4_step, - &ux_confirm_full_flow_5_step, - &ux_confirm_full_flow_6_step); + &ux_confirm_full_flow_1_step, + &ux_confirm_full_flow_2_step, + &ux_confirm_full_flow_3_step, + &ux_confirm_full_flow_4_step, + &ux_confirm_full_flow_5_step, + &ux_confirm_full_flow_6_step +); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, {&C_icon_eye, "Review", "transaction"}); -UX_STEP_NOCB(ux_confirm_single_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount, - }); -UX_STEP_NOCB(ux_confirm_single_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB(ux_confirm_single_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID(ux_confirm_single_flow_5_step, - pb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - }); -UX_STEP_VALID(ux_confirm_single_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB( + ux_confirm_single_flow_1_step, + pnn, + { + &C_icon_eye, + "Review", + "transaction" + }); +UX_STEP_NOCB( + ux_confirm_single_flow_2_step, + bnnn_paging, + { + .title = "Amount", + .text = vars.tmp.fullAmount, + }); +UX_STEP_NOCB( + ux_confirm_single_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB( + ux_confirm_single_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID( + ux_confirm_single_flow_5_step, + pb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + }); +UX_STEP_VALID( + ux_confirm_single_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: fullAddress UX_FLOW(ux_confirm_single_flow, - &ux_confirm_single_flow_1_step, - &ux_confirm_single_flow_2_step, - &ux_confirm_single_flow_3_step, - &ux_confirm_single_flow_4_step, - &ux_confirm_single_flow_5_step, - &ux_confirm_single_flow_6_step); + &ux_confirm_single_flow_1_step, + &ux_confirm_single_flow_2_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_4_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_finalize_flow_1_step, pnn, {&C_icon_eye, "Review", "transaction"}); -UX_STEP_NOCB(ux_finalize_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID(ux_finalize_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - {&C_icon_validate_14, "Accept", "and send"}); -UX_STEP_VALID(ux_finalize_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB( + ux_finalize_flow_1_step, + pnn, + { + &C_icon_eye, + "Review", + "transaction" + }); +UX_STEP_NOCB( + ux_finalize_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID( + ux_finalize_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + "and send" + }); +UX_STEP_VALID( + ux_finalize_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // finalize: confirm transaction / Fees: feesAmount UX_FLOW(ux_finalize_flow, - &ux_finalize_flow_1_step, - &ux_finalize_flow_4_step, - &ux_finalize_flow_5_step, - &ux_finalize_flow_6_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_display_public_flow_1_step, - pnn, - { - &C_icon_warning, - "The derivation", - "path is unusual!", - }); -UX_STEP_NOCB(ux_display_public_flow_2_step, - bnnn_paging, - { - .title = "Derivation path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_VALID(ux_display_public_flow_3_step, - pnn, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_NOCB(ux_display_public_flow_4_step, - pnn, - { - &C_icon_validate_14, - "Approve derivation", - "path", - }); -UX_STEP_NOCB(ux_display_public_flow_5_step, - bnnn_paging, - { - .title = "Address", - .text = G_io_apdu_buffer + 200, - }); -UX_STEP_VALID(ux_display_public_flow_6_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); -UX_STEP_VALID(ux_display_public_flow_7_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_public_with_warning_flow, - &ux_display_public_flow_1_step, - &ux_display_public_flow_2_step, - &ux_display_public_flow_3_step, - &ux_display_public_flow_4_step, - FLOW_BARRIER, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step); - -UX_FLOW(ux_display_public_flow, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_VALID(ux_display_token_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Confirm token", - G_io_apdu_buffer + 200, - }); -UX_STEP_VALID(ux_display_token_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_token_flow, &ux_display_token_flow_1_step, &ux_display_token_flow_2_step); + &ux_finalize_flow_1_step, + &ux_finalize_flow_4_step, + &ux_finalize_flow_5_step, + &ux_finalize_flow_6_step +); ////////////////////////////////////////////////////////////////////// -UX_STEP_VALID(ux_request_pubkey_approval_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Export", - "public key?", - }); -UX_STEP_VALID(ux_request_pubkey_approval_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_request_pubkey_approval_flow, - &ux_request_pubkey_approval_flow_1_step, - &ux_request_pubkey_approval_flow_2_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_request_change_path_approval_flow_1_step, - pbb, - { - &C_icon_eye, - "The change path", - "is unusual", - }); -UX_STEP_NOCB(ux_request_change_path_approval_flow_2_step, - bnnn_paging, - { - .title = "Change path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_VALID(ux_request_change_path_approval_flow_3_step, - pbb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_VALID(ux_request_change_path_approval_flow_4_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); +UX_STEP_NOCB( + ux_request_change_path_approval_flow_1_step, + pbb, + { + &C_icon_eye, + "The change path", + "is unusual", + }); +UX_STEP_NOCB( + ux_request_change_path_approval_flow_2_step, + bnnn_paging, + { + .title = "Change path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_VALID( + ux_request_change_path_approval_flow_3_step, + pbb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_VALID( + ux_request_change_path_approval_flow_4_step, + pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); UX_FLOW(ux_request_change_path_approval_flow, - &ux_request_change_path_approval_flow_1_step, - &ux_request_change_path_approval_flow_2_step, - &ux_request_change_path_approval_flow_3_step, - &ux_request_change_path_approval_flow_4_step); - -#endif // TARGET_NANOX || TARGET_NANOS2 + &ux_request_change_path_approval_flow_1_step, + &ux_request_change_path_approval_flow_2_step, + &ux_request_change_path_approval_flow_3_step, + &ux_request_change_path_approval_flow_4_step +); -void ui_idle(void) { - ux_step_count = 0; - ux_loop_over_curr_element = 0; - -#elif defined(TARGET_NANOS) - UX_MENU_DISPLAY(0, menu_main, NULL); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - // reserve a display stack slot if none yet - if (G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_idle_flow, NULL); -#endif // #if TARGET_ID -} +#endif // TARGET_NANOX || TARGET_NANOS2 #ifndef TARGET_FATSTACKS // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { - io_seproxyhal_display_default((bagl_element_t *) element); + io_seproxyhal_display_default((bagl_element_t *)element); } } #endif unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; + case CHANNEL_KEYBOARD: + break; - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); + // multiplexed io exchange over a SPI channel and TLV encapsulated protocol + case CHANNEL_SPI: + if (tx_len) { + io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); + if (channel & IO_RESET_AFTER_REPLIED) { + reset(); } + return 0; // nothing received from the master so far (it's a tx + // transaction) + } else { + return io_seproxyhal_spi_recv(G_io_apdu_buffer, + sizeof(G_io_apdu_buffer), 0); + } - default: - THROW(INVALID_PARAMETER); + default: + THROW(INVALID_PARAMETER); } return 0; } @@ -1074,9 +730,9 @@ unsigned char io_event(unsigned char channel) { // can't have more than one tag in the reply, not supported yet. switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); + break; #ifndef TARGET_FATSTACKS case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: @@ -1100,24 +756,20 @@ unsigned char io_event(unsigned char channel) { break; #endif - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { - // don't redisplay if UX not allowed (pin locked in the common bolos - // ux ?) - if (ux_step_count && UX_ALLOWED) { - // prepare next screen - if (!ux_loop_over_curr_element) { - ux_step = (ux_step + 1) % ux_step_count; - } - // redisplay screen - UX_REDISPLAY(); + case SEPROXYHAL_TAG_TICKER_EVENT: + UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { + // don't redisplay if UX not allowed (pin locked in the common bolos + // ux ?) + if (ux_step_count && UX_ALLOWED) { + // prepare next screen + if(!ux_loop_over_curr_element) { + ux_step = (ux_step + 1) % ux_step_count; } - }); - break; + // redisplay screen + UX_REDISPLAY(); + } + }); + break; } // close the event if not done previously (by a display or whatever) @@ -1136,25 +788,24 @@ uint8_t prepare_fees() { } else { unsigned char fees[8]; unsigned short textSize; - if (transaction_amount_sub_be(fees, - btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.totalOutputAmount)) { + if (transaction_amount_sub_be( + fees, btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.totalOutputAmount)) { PRINTF("Fees: %.*H\n", 8, fees); - PRINTF("transactionAmount:: %.*H\n", - 8, - btchip_context_D.transactionContext.transactionAmount); + PRINTF("transactionAmount:: %.*H\n", 8, btchip_context_D.transactionContext.transactionAmount); PRINTF("totalOutputAmount: %.*H\n", 8, btchip_context_D.totalOutputAmount); PRINTF("Error : Fees not consistent"); goto error; } - os_memmove(vars.tmp.feesAmount, - btchip_context_D.shortCoinId, + os_memmove(vars.tmp.feesAmount, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *) (vars.tmp.feesAmount + btchip_context_D.shortCoinIdLength + 1); + (unsigned char *)(vars.tmp.feesAmount + + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; + vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = + '\0'; } return 1; error: @@ -1169,9 +820,9 @@ uint8_t prepare_single_output() { unsigned char versionSize; int addressOffset; unsigned char address[22]; - unsigned short version; // addr prefix, or net id + unsigned short version; // addr prefix, or net id unsigned short textSize; - unsigned char script_version[2]; // Decred thing + unsigned char script_version[2]; // Decred thing vars.tmp.fullAddress[0] = '\0'; btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); @@ -1182,16 +833,21 @@ uint8_t prepare_single_output() { PRINTF("amount: %.*H\n", 8, amount); - if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset)) { + if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + + offset)) { strcpy(vars.tmp.fullAddress, "OP_RETURN"); - } else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)) { + } + else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + + offset)) { addressOffset = offset + 4; version = btchip_context_D.payToAddressVersion; - } else { + } + else { addressOffset = offset + 3; version = btchip_context_D.payToScriptHashVersion; } if (vars.tmp.fullAddress[0] == 0) { + if (version > 255) { versionSize = 2; address[0] = (version >> 8); @@ -1200,15 +856,13 @@ uint8_t prepare_single_output() { versionSize = 1; address[0] = version; } - os_memmove(address + versionSize, btchip_context_D.currentOutput + addressOffset, 20); + os_memmove(address + versionSize, + btchip_context_D.currentOutput + addressOffset, 20); // Prepare address - textSize = btchip_public_key_to_encoded_base58(address, - 20 + versionSize, - (unsigned char *) tmp, - sizeof(tmp), - version, - 1); + textSize = btchip_public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)tmp, + sizeof(tmp), version, 1); tmp[textSize] = '\0'; strcpy(vars.tmp.fullAddress, tmp); @@ -1216,14 +870,15 @@ uint8_t prepare_single_output() { // Prepare amount - os_memmove(vars.tmp.fullAmount, - btchip_context_D.shortCoinId, + os_memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *) (vars.tmp.fullAmount + btchip_context_D.shortCoinIdLength + 1); + (unsigned char *)(vars.tmp.fullAmount + + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; + vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = + '\0'; return 1; } @@ -1237,7 +892,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) { unsigned char amount[8], totalOutputAmount[8], fees[8]; char tmp[80]; unsigned char outputPos = 0, changeFound = 0; - unsigned char script_version[2]; // Decred thing + unsigned char script_version[2]; // Decred thing if (btchip_context_D.transactionContext.relaxed && !btchip_context_D.transactionContext.consumeP2SH) { @@ -1279,17 +934,20 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); transaction_amount_add_be(totalOutputAmount, totalOutputAmount, amount); - offset += 8; // skip amount + offset += 8; // skip amount btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version - - isOpReturn = btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset); - isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + offset); - isOpCreate = btchip_output_script_is_op_create(btchip_context_D.currentOutput + offset); - isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + offset); - PRINTF("REGULAR SCRIPT: %d\n", - btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); + offset += 2; // skip script_version + + isOpReturn = btchip_output_script_is_op_return( + btchip_context_D.currentOutput + offset); + isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + + offset); + isOpCreate = btchip_output_script_is_op_create( + btchip_context_D.currentOutput + offset); + isOpCall = btchip_output_script_is_op_call( + btchip_context_D.currentOutput + offset); + PRINTF("REGULAR SCRIPT: %d\n", btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); // Always notify OP_RETURN to the user if (nullAmount && isOpReturn) { if (!checkOnly) { @@ -1297,14 +955,17 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } goto error; } - if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + offset) && !isP2sh && - !(nullAmount && isOpReturn) && (!isOpCreate && !isOpCall)) { + if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + + offset) && + !isP2sh && !(nullAmount && isOpReturn) && + (!isOpCreate && !isOpCall)) { if (!checkOnly) { PRINTF("Error : Unrecognized input script"); } goto error; - } else if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + offset) && - !isP2sh && !(nullAmount && isOpReturn)) { + } else if (!btchip_output_script_is_regular( + btchip_context_D.currentOutput + offset) && + !isP2sh && !(nullAmount && isOpReturn)) { if (!checkOnly) { PRINTF("Error : Unrecognized input script"); } @@ -1312,8 +973,10 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { unsigned char addressOffset = - (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (os_memcmp(btchip_context_D.currentOutput + offset + addressOffset, + (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH + : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (os_memcmp(btchip_context_D.currentOutput + offset + + addressOffset, btchip_context_D.tmpCtx.output.changeAddress + 1, 20) == 0) { if (changeFound) { @@ -1337,9 +1000,9 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } goto error; } - if (transaction_amount_sub_be(fees, - btchip_context_D.transactionContext.transactionAmount, - totalOutputAmount)) { + if (transaction_amount_sub_be( + fees, btchip_context_D.transactionContext.transactionAmount, + totalOutputAmount)) { PRINTF("tx_amount: ", 8, btchip_context_D.transactionContext.transactionAmount); PRINTF("total_amount: ", 8, totalOutputAmount); if (!checkOnly) { @@ -1351,51 +1014,48 @@ uint8_t prepare_full_output(uint8_t checkOnly) { // Format validation message currentPos = 0; offset = 1; - btchip_context_D.tmp = (unsigned char *) tmp; + btchip_context_D.tmp = (unsigned char *)tmp; for (i = 0; i < numberOutputs; i++) { - if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + - 2)) { + if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + 2)) { unsigned char versionSize; int addressOffset; unsigned char address[22]; unsigned short version; btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); - offset += 8; // skip amount + offset += 8; // skip amount btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version + offset += 2; // skip script_version - if (btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)) { + if (btchip_output_script_is_regular( + btchip_context_D.currentOutput + offset)) { addressOffset = offset + 4; version = btchip_context_D.payToAddressVersion; - } else { + } else { addressOffset = offset + 3; version = btchip_context_D.payToScriptHashVersion; } - if (version > 255) { + if (version > 255) { versionSize = 2; address[0] = (version >> 8); address[1] = version; - } else { + } else { versionSize = 1; address[0] = version; } os_memmove(address + versionSize, - btchip_context_D.currentOutput + addressOffset, - 20); + btchip_context_D.currentOutput + addressOffset, + 20); // if we're processing the real output (not the change one) if (currentPos == outputPos) { unsigned short textSize = 0; // Prepare address - textSize = btchip_public_key_to_encoded_base58(address, - 20 + versionSize, - (unsigned char *) tmp, - sizeof(tmp), - version, - 1); + textSize = btchip_public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)tmp, + sizeof(tmp), version, 1); tmp[textSize] = '\0'; strcpy(vars.tmp.fullAddress, tmp); @@ -1406,24 +1066,34 @@ uint8_t prepare_full_output(uint8_t checkOnly) { os_memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); - vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; + vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = + ' '; btchip_context_D.tmp = - (unsigned char *) (vars.tmp.fullAmount + - btchip_context_D.shortCoinIdLength + 1); + (unsigned char *)(vars.tmp.fullAmount + + btchip_context_D.shortCoinIdLength + + 1); textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; + vars.tmp + .fullAmount[textSize + + btchip_context_D.shortCoinIdLength + 1] = + '\0'; // prepare fee display PRINTF("prepare fee display\n"); os_memmove(vars.tmp.feesAmount, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); - vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; + vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = + ' '; btchip_context_D.tmp = - (unsigned char *) (vars.tmp.feesAmount + - btchip_context_D.shortCoinIdLength + 1); + (unsigned char *)(vars.tmp.feesAmount + + btchip_context_D.shortCoinIdLength + + 1); textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; + vars.tmp + .feesAmount[textSize + + btchip_context_D.shortCoinIdLength + 1] = + '\0'; break; } } else { @@ -1443,20 +1113,11 @@ uint8_t prepare_full_output(uint8_t checkOnly) { uint8_t prepare_message_signature() { uint8_t buffer[32]; - cx_hash(&btchip_context_D.transactionHashWitness.header, - CX_LAST, - vars.tmp.fullAmount, - 0, - buffer, - 32); - - snprintf(vars.tmp.fullAddress, - sizeof(vars.tmp.fullAddress), - "%.*H...%.*H", - 8, - buffer, - 8, - buffer + 32 - 8); + cx_hash(&btchip_context_D.transactionHashWitness.header, CX_LAST, + vars.tmp.fullAmount, 0, buffer, 32); + + snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H...%.*H", + 8, buffer, 8, buffer + 32 - 8); return 1; } @@ -1471,7 +1132,7 @@ unsigned int btchip_bagl_confirm_full_output() { UX_DISPLAY(ui_verify_nanos, ui_verify_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_confirm_full_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } @@ -1481,10 +1142,9 @@ unsigned int btchip_bagl_confirm_single_output() { return 0; } - snprintf(vars.tmp.feesAmount, - sizeof(vars.tmp.feesAmount), - "output #%d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1); + snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + + 1); #if defined(TARGET_NANOS) ux_step = 0; @@ -1492,7 +1152,7 @@ unsigned int btchip_bagl_confirm_single_output() { UX_DISPLAY(ui_verify_output_nanos, ui_verify_output_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_confirm_single_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } @@ -1507,7 +1167,7 @@ unsigned int btchip_bagl_finalize_tx() { UX_DISPLAY(ui_finalize_nanos, ui_finalize_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_finalize_flow, NULL); -#endif // TARGET_NANOX +#endif // TARGET_NANOX return 1; } @@ -1522,57 +1182,11 @@ void btchip_bagl_confirm_message_signature() { UX_DISPLAY(ui_verify_message_signature_nanos, ui_verify_message_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_sign_flow, NULL); -#endif // TARGET_NANOX -} - -void btchip_bagl_display_public_key(unsigned char *derivation_path) { - // append a white space at the end of the address to avoid glitch on nano S - strcat(G_io_apdu_buffer + 200, " "); - - bip32_print_path(derivation_path, - vars.tmp_warning.derivation_path, - MAX_DERIV_PATH_ASCII_LENGTH); - uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); - -#if defined(TARGET_NANOS) - // prepend a white space to the address - G_io_apdu_buffer[199] = ' '; - ux_step = is_derivation_path_unusual ? 0 : 4; - ux_step_count = 6; - UX_DISPLAY(ui_display_address_nanos, ui_display_address_nanos_prepro); - -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init( - 0, - is_derivation_path_unusual ? ux_display_public_with_warning_flow : ux_display_public_flow, - NULL); -#endif // TARGET_NANOX +#endif // TARGET_NANOX } -void btchip_bagl_display_token() +void btchip_bagl_request_change_path_approval(unsigned char* change_path) { -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 1; - UX_DISPLAY(ui_display_token_nanos, NULL); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, ux_display_token_flow, NULL); -#endif // #if TARGET_ID -} - -void btchip_bagl_request_pubkey_approval() -{ -#if defined(TARGET_NANOS) - // append and prepend a white space to the address - ux_step = 0; - ux_step_count = 1; - UX_DISPLAY(ui_request_pubkey_approval_nanos, NULL); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); -#endif // #if TARGET_ID -} - -void btchip_bagl_request_change_path_approval(unsigned char *change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); #if defined(TARGET_NANOS) // append and prepend a white space to the address @@ -1581,7 +1195,7 @@ void btchip_bagl_request_change_path_approval(unsigned char *change_path) { UX_DISPLAY(ui_request_change_path_approval_nanos, ui_request_change_path_approval_nanos_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_request_change_path_approval_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } void app_exit(void) { @@ -1607,10 +1221,10 @@ btchip_altcoin_config_t const C_coin_config = { #ifdef COIN_FORKID .forkid = COIN_FORKID, -#endif // COIN_FORKID +#endif // COIN_FORKID #ifdef COIN_FLAGS .flags = COIN_FLAGS, -#endif // COIN_FLAGS +#endif // COIN_FLAGS .kind = COIN_KIND, }; @@ -1638,7 +1252,7 @@ __attribute__((section(".boot"))) int main(int arg0) { check_api_level(CX_COMPAT_APILEVEL); // delegate to bitcoin app/lib libcall_params[0] = "Decred"; - libcall_params[1] = 0x100; // use the Init call, as we won't exit + libcall_params[1] = 0x100; // use the Init call, as we won't exit libcall_params[2] = &coin_config; os_lib_call(&libcall_params); } @@ -1654,14 +1268,14 @@ __attribute__((section(".boot"))) int main(int arg0) { if (arg0) { // is ID 1 ? - if (((unsigned int *) arg0)[0] != 0x100) { + if (((unsigned int *)arg0)[0] != 0x100) { app_exit(); return 0; } // grab the coin config structure from the first parameter - G_coin_config = (btchip_altcoin_config_t *) ((unsigned int *) arg0)[1]; + G_coin_config = (btchip_altcoin_config_t *)((unsigned int *)arg0)[1]; } else { - G_coin_config = (btchip_altcoin_config_t *) PIC(&C_coin_config); + G_coin_config = (btchip_altcoin_config_t *)PIC(&C_coin_config); } // ensure exception will work as planned @@ -1676,7 +1290,7 @@ __attribute__((section(".boot"))) int main(int arg0) { #ifdef TARGET_NANOX // grab the current plane mode setting G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX +#endif // TARGET_NANOX btchip_context_init(); @@ -1688,7 +1302,7 @@ __attribute__((section(".boot"))) int main(int arg0) { #ifdef HAVE_BLE BLE_power(0, NULL); BLE_power(1, "Nano X"); -#endif // HAVE_BLE +#endif // HAVE_BLE app_main(); } @@ -1707,6 +1321,6 @@ __attribute__((section(".boot"))) int main(int arg0) { END_TRY; } app_exit(); -#endif // USE_LIB_DECRED +#endif // USE_LIB_DECRED return 0; } diff --git a/src/ui/pubkey/ui_pubkey.h b/src/ui/pubkey/ui_pubkey.h new file mode 100644 index 0000000..da0f52f --- /dev/null +++ b/src/ui/pubkey/ui_pubkey.h @@ -0,0 +1,21 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#pragma once + +void btchip_bagl_display_public_key(unsigned char* derivation_path); +void btchip_bagl_request_pubkey_approval(void); +void btchip_bagl_display_token(void); diff --git a/src/ui/pubkey/ui_pubkey_bagl.c b/src/ui/pubkey/ui_pubkey_bagl.c new file mode 100644 index 0000000..6bc73b3 --- /dev/null +++ b/src/ui/pubkey/ui_pubkey_bagl.c @@ -0,0 +1,364 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#ifdef HAVE_BAGL +#include "ui_main_menu.h" +#include "ui_shared.h" +#include "os.h" +#include "os_io_seproxyhal.h" +#include "ux.h" +#include "string.h" + +#include "btchip_internal.h" +#include "ui_shared.h" + +#if defined(TARGET_NANOS) + +unsigned int ui_display_address_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); +unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); +unsigned int ui_display_token_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); + +const bagl_element_t ui_display_address_nanos[] = { + + UI_NANOS_BACKGROUND(), + + /* Displayed when derivation path is unusual */ + + UI_NANOS_TEXT(1, 0, 22, 128, "Warning !", BAGL_FONT_OPEN_SANS_LIGHT_16px), + + UI_NANOS_TEXT(2, 0, 12, 128, "The derivation", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(2, 0, 26, 128, "path is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(3, 0, 12, 128, "Derivation path", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + /* Always displayed */ + + UI_NANOS_ICON_LEFT(5, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(5, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(5, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(5, 0, 26, 128, "address", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(6, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), + // Hax, avoid wasting space + UI_NANOS_SCROLLING_TEXT(0x86, 15, 26, 98, G_io_apdu_buffer + 199, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; + +const bagl_element_t ui_request_pubkey_approval_nanos[] = { + UI_NANOS_BACKGROUND(), + UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(1, 0, 12, 128, "Export", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + // Hax, avoid wasting space + UI_NANOS_TEXT(1, 0, 26, 128, "public key?", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; + +const bagl_element_t ui_display_token_nanos[] = { + + UI_NANOS_BACKGROUND(), + UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(1, 0, 12, 128, "Confirm token", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + // Hax, avoid wasting space + UI_NANOS_TEXT(1, 0, 26, 128, G_io_apdu_buffer + 200, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; + + +unsigned int ui_display_address_nanos_prepro(const bagl_element_t *element) { + + if (element->component.userid > 0) { + unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); + if (display) { + switch (element->component.userid) { + case 0x83: + ux_loop_over_curr_element = 1; + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; + case 5: + UX_CALLBACK_SET_INTERVAL(2000); + ux_loop_over_curr_element = 0; // allow next timer to increment ux_step when triggered + break; + case 0x86: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + // ugly ux tricks, loops around last 2 screens + ux_step -= 1; // loops back to previous element on next redraw + ux_loop_over_curr_element = 1; // when the timer will trigger, ux_step won't be incremented, only redraw + break; + } + } + return display; + } + return 1; +} + +unsigned int ui_display_address_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { + if (ux_step == 3) + { + switch (button_mask) + { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); + break; + } + } + else if (ux_step >= 4) + { + switch (button_mask) + { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; + } + } + else + { + if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) + { + // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) + if(ux_loop_over_curr_element) { + ux_loop_over_curr_element = 0; + ux.callback_interval_ms = 0; + } + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); + } + } + return 0; +} + +unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) +{ + switch (button_mask) + { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; + } + return 0; +} + +unsigned int ui_display_token_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) +{ + switch (button_mask) + { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_token_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_token_ok(NULL); + break; + } + return 0; +} + +#endif + +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) + +UX_STEP_NOCB( + ux_display_public_flow_1_step, + pnn, + { + &C_icon_warning, + "The derivation", + "path is unusual!", + }); +UX_STEP_NOCB( + ux_display_public_flow_2_step, + bnnn_paging, + { + .title = "Derivation path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_VALID( + ux_display_public_flow_3_step, + pnn, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_NOCB( + ux_display_public_flow_4_step, + pnn, + { + &C_icon_validate_14, + "Approve derivation", + "path", + }); +UX_STEP_NOCB( + ux_display_public_flow_5_step, + bnnn_paging, + { + .title = "Address", + .text = G_io_apdu_buffer+200, + }); +UX_STEP_VALID( + ux_display_public_flow_6_step, + pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); +UX_STEP_VALID( + ux_display_public_flow_7_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_display_public_with_warning_flow, + &ux_display_public_flow_1_step, + &ux_display_public_flow_2_step, + &ux_display_public_flow_3_step, + &ux_display_public_flow_4_step, + FLOW_BARRIER, + &ux_display_public_flow_5_step, + &ux_display_public_flow_6_step, + &ux_display_public_flow_7_step +); + +UX_FLOW(ux_display_public_flow, + &ux_display_public_flow_5_step, + &ux_display_public_flow_6_step, + &ux_display_public_flow_7_step +); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_VALID( + ux_request_pubkey_approval_flow_1_step, + pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Export", + "public key?", + }); +UX_STEP_VALID( + ux_request_pubkey_approval_flow_2_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_request_pubkey_approval_flow, + &ux_request_pubkey_approval_flow_1_step, + &ux_request_pubkey_approval_flow_2_step +); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_VALID( + ux_display_token_flow_1_step, + pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Confirm token", + G_io_apdu_buffer+200, + }); +UX_STEP_VALID( + ux_display_token_flow_2_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_display_token_flow, + &ux_display_token_flow_1_step, + &ux_display_token_flow_2_step +); + +#endif + +void btchip_bagl_display_public_key(unsigned char* derivation_path) { + // append a white space at the end of the address to avoid glitch on nano S + strcat(G_io_apdu_buffer + 200, " "); + + bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); + uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); + +#if defined(TARGET_NANOS) + // prepend a white space to the address + G_io_apdu_buffer[199] = ' '; + ux_step = is_derivation_path_unusual?0:4; + ux_step_count = 6; + UX_DISPLAY(ui_display_address_nanos, ui_display_address_nanos_prepro); + +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, is_derivation_path_unusual?ux_display_public_with_warning_flow:ux_display_public_flow, NULL); +#endif // TARGET_NANOX +} + +void btchip_bagl_request_pubkey_approval(void) +{ +#if defined(TARGET_NANOS) + // append and prepend a white space to the address + ux_step = 0; + ux_step_count = 1; + UX_DISPLAY(ui_request_pubkey_approval_nanos, NULL); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); +#endif // #if TARGET_ID +} + +void btchip_bagl_display_token(void) +{ +#if defined(TARGET_NANOS) + ux_step = 0; + ux_step_count = 1; + UX_DISPLAY(ui_display_token_nanos, NULL); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, ux_display_token_flow, NULL); +#endif // #if TARGET_ID +} +#endif // HAVE_BAGL diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 60c4308..e109fe7 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -19,3 +19,4 @@ unsigned int ux_step; unsigned int ux_step_count; uint8_t ux_loop_over_curr_element; +vars_u_t vars; diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 16973dc..95fb58e 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -18,7 +18,44 @@ #pragma once #include +#include "btchip_filesystem_tx.h" +#include "ux.h" +#define COLOR_WHITE 0xFFFFFF +#define UI_NANOS_BACKGROUND() {{BAGL_RECTANGLE,0,0,0,128,32,0,0,BAGL_FILL,0,COLOR_WHITE,0,0},NULL,0,0,0,NULL,NULL,NULL} +#define UI_NANOS_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,0},(char *)text,0,0,0,NULL,NULL,NULL} +#define UI_NANOS_ICON_LEFT(userid, glyph) {{BAGL_ICON,userid,3,12,7,7,0,0,0,COLOR_WHITE,0,0,glyph},NULL,0,0,0,NULL,NULL,NULL} +#define UI_NANOS_ICON_RIGHT(userid, glyph) {{BAGL_ICON,userid,117,13,8,6,0,0,0,COLOR_WHITE,0,0,glyph},NULL,0,0,0,NULL,NULL,NULL} +// Only one scrolling text per screen can be displayed +#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0x80|10,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,26},(char *)text,0,0,0,NULL,NULL,NULL} + +typedef union { + struct { + // char addressSummary[40]; // beginning of the output address ... end + // of + + char fullAddress[43]; // the address + char fullAmount[20]; // full amount + char feesAmount[20]; // fees + } tmp; + + struct { + char derivation_path [MAX_DERIV_PATH_ASCII_LENGTH]; + } tmp_warning; + + /* + struct { + bagl_icon_details_t icon_details; + unsigned int colors[2]; + unsigned char qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(3)]; + } tmpqr; + + unsigned int dummy; // ensure the whole vars is aligned for the CM0 to + operate correctly + */ +} vars_u_t; + +extern vars_u_t vars; extern unsigned int ux_step; extern unsigned int ux_step_count; extern uint8_t ux_loop_over_curr_element; From 0f2df8c232b3f7116dc708101a87fe10dc549d78 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Fri, 25 Nov 2022 14:51:21 +0100 Subject: [PATCH 09/41] Add Stax address approval UX screens. --- Makefile | 16 ++--- src/main.c | 18 ----- src/ui/pubkey/ui_pubkey_bagl.c | 3 +- src/ui/pubkey/ui_pubkey_nbgl.c | 128 +++++++++++++++++++++++++++++++++ src/ui/ui_shared.c | 23 ++++++ src/ui/ui_shared.h | 3 +- 6 files changed, 162 insertions(+), 29 deletions(-) create mode 100644 src/ui/pubkey/ui_pubkey_nbgl.c diff --git a/Makefile b/Makefile index 7b0d89d..ab3f366 100755 --- a/Makefile +++ b/Makefile @@ -76,11 +76,6 @@ all: default # Platform # ############ -ifneq ($(TARGET_NAME),TARGET_FATSTACKS) - DEFINES += HAVE_BAGL - DEFINES += NBGL_QRCODE -endif - DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU @@ -99,6 +94,11 @@ DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" DEFINES += UNUSED\(x\)=\(void\)x DEFINES += APPVERSION=\"$(APPVERSION)\" +ifeq ($(TARGET_NAME),TARGET_FATSTACKS) + DEFINES += NBGL_QRCODE NBGL_USE_CASE NBGL_PAGE +else + DEFINES += HAVE_BAGL +endif ifeq ($(TARGET_NAME),TARGET_NANOX) DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 @@ -165,13 +165,13 @@ include $(BOLOS_SDK)/Makefile.glyphs ### variables processed by the common makefile.rules of the SDK to grab source files and include dirs APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f qrcode +SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f ifeq ($(TARGET_NAME),TARGET_FATSTACKS) SDK_SOURCE_PATH += lib_nbgl/src -SDK_SOURCE_PATH += lib_nbgl/src +SDK_SOURCE_PATH += lib_ux_fatstacks else -SDK_SOURCE_PATH += lib_ux +SDK_SOURCE_PATH += lib_ux qrcode endif ifeq ($(TARGET_NAME),TARGET_NANOX) diff --git a/src/main.c b/src/main.c index 7768fa4..3300855 100644 --- a/src/main.c +++ b/src/main.c @@ -59,8 +59,6 @@ unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e); unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e); @@ -316,22 +314,6 @@ io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { return 0; // DO NOT REDRAW THE BUTTON } -unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { - // user denied the transaction, tell the USB side - btchip_bagl_user_action_display(0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { - // user accepted the transaction, tell the USB side - btchip_bagl_user_action_display(1); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e) { // revoke previous valid token if there was one btchip_context_D.has_valid_token = false; diff --git a/src/ui/pubkey/ui_pubkey_bagl.c b/src/ui/pubkey/ui_pubkey_bagl.c index 6bc73b3..e01ab7a 100644 --- a/src/ui/pubkey/ui_pubkey_bagl.c +++ b/src/ui/pubkey/ui_pubkey_bagl.c @@ -16,14 +16,13 @@ ********************************************************************************/ #ifdef HAVE_BAGL #include "ui_main_menu.h" +#include "ui_pubkey.h" #include "ui_shared.h" #include "os.h" #include "os_io_seproxyhal.h" #include "ux.h" #include "string.h" - #include "btchip_internal.h" -#include "ui_shared.h" #if defined(TARGET_NANOS) diff --git a/src/ui/pubkey/ui_pubkey_nbgl.c b/src/ui/pubkey/ui_pubkey_nbgl.c new file mode 100644 index 0000000..e88747d --- /dev/null +++ b/src/ui/pubkey/ui_pubkey_nbgl.c @@ -0,0 +1,128 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#ifdef HAVE_NBGL +#include // bool +#include // memset + +#include "os.h" +#include "os_io_seproxyhal.h" +#include "ux.h" +#include "nbgl_use_case.h" + +#include "ui_main_menu.h" +#include "ui_pubkey.h" +#include "ui_shared.h" +#include "btchip_internal.h" + +typedef enum { + DISPLAY_ADDRESS = 0, + EXPORT_REQUEST, + DISPLAY_TOKEN, +} pubkey_display_usecase_t; + +static char confirm_text[20]; +static char choice_text[70]; +static pubkey_display_usecase_t display_type; + +static void confirmationChoiceClbk(bool confirm) { + explicit_bzero(confirm_text, sizeof(confirm_text)); + switch(display_type){ + case DISPLAY_ADDRESS: + if(confirm) + { + strncpy(confirm_text,"ADDRESS\nAPPROVED", sizeof(confirm_text)); + } + else + { + strncpy(confirm_text,"Address rejected", sizeof(confirm_text)); + } + break; + case EXPORT_REQUEST: + if(confirm) + { + strncpy(confirm_text,"PUBLIC KEY\nEXPORTED", sizeof(confirm_text)); + } + else + { + strncpy(confirm_text,"Export cancelled", sizeof(confirm_text)); + } + break; + case DISPLAY_TOKEN: + if(confirm) + { + strncpy(confirm_text,"TOKEN\nAPPROVED", sizeof(confirm_text)); + } + else + { + strncpy(confirm_text,"Token rejected", sizeof(confirm_text)); + } + break; + default: + PRINTF("Should not happen !\n"); + break; + } + confirm ? io_seproxyhal_touch_display_ok(NULL) : io_seproxyhal_touch_display_cancel(NULL); + nbgl_useCaseStatus(confirm_text,confirm,ui_idle); +} + +static void warningChoiceClbk(bool reject) { + if (reject) { + io_seproxyhal_touch_display_cancel(NULL); + nbgl_useCaseStatus("Address rejected",false,ui_idle); + } + else { + nbgl_useCaseAddressConfirmation((char*)G_io_apdu_buffer+200,confirmationChoiceClbk); + } +} + +void btchip_bagl_display_public_key(unsigned char* derivation_path) { + display_type = DISPLAY_ADDRESS; + bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); + uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); + if(is_derivation_path_unusual) + { + explicit_bzero(choice_text, sizeof(choice_text)); + snprintf(choice_text, + sizeof(choice_text), + "WARNING !\nThe derivation path is\nunusual :\n%s", + vars.tmp_warning.derivation_path); + nbgl_useCaseChoice(choice_text,"Reject if you're not sure","Reject","Continue",warningChoiceClbk); + } + else + { + nbgl_useCaseAddressConfirmation((char*)G_io_apdu_buffer+200,confirmationChoiceClbk); + } +} + +void btchip_bagl_request_pubkey_approval(void) +{ + display_type = EXPORT_REQUEST; + nbgl_useCaseChoice("Export public key ?",NULL,"Export","Cancel",confirmationChoiceClbk); +} + +void btchip_bagl_display_token(void) +{ + display_type = DISPLAY_TOKEN; + explicit_bzero(choice_text, sizeof(choice_text)); + snprintf(choice_text, + sizeof(choice_text), + "Approve token :\n%s", + (char*)G_io_apdu_buffer+200); + nbgl_useCaseChoice(choice_text,NULL,"Approve","Reject",confirmationChoiceClbk); +} + +#endif // HAVE_NBGL diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index e109fe7..34e01d5 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -15,8 +15,31 @@ * limitations under the License. ********************************************************************************/ #include "ui_shared.h" +#include "btchip_bagl_extensions.h" unsigned int ux_step; unsigned int ux_step_count; uint8_t ux_loop_over_curr_element; vars_u_t vars; + +unsigned int io_seproxyhal_touch_display_cancel(const void* e){ + UNUSED(e); + // user denied the transaction, tell the USB side + btchip_bagl_user_action_display(0); + // redraw ui +#ifndef HAVE_NBGL + ui_idle(); +#endif + return 0; // DO NOT REDRAW THE BUTTON +} + +unsigned int io_seproxyhal_touch_display_ok(const void* e){ + UNUSED(e); + // user accepted the transaction, tell the USB side + btchip_bagl_user_action_display(1); + // redraw ui +#ifndef HAVE_NBGL + ui_idle(); +#endif + return 0; // DO NOT REDRAW THE BUTTON +} diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 95fb58e..3882a83 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -60,4 +60,5 @@ extern unsigned int ux_step; extern unsigned int ux_step_count; extern uint8_t ux_loop_over_curr_element; -// unsigned int io_seproxyhal_touch_tx_ok(const void *e); +unsigned int io_seproxyhal_touch_display_cancel(const void* e); +unsigned int io_seproxyhal_touch_display_ok(const void* e); From c20c845bc4bb4f4944442e7cd4b0dee00e0c0c65 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Fri, 25 Nov 2022 15:01:10 +0100 Subject: [PATCH 10/41] Rename address approval UX functions. --- src/btchip_apdu_get_wallet_public_key.c | 110 ++++++++++++------------ src/ui/pubkey/ui_pubkey.h | 6 +- src/ui/pubkey/ui_pubkey_bagl.c | 6 +- src/ui/pubkey/ui_pubkey_nbgl.c | 6 +- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 0505419..540286d 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -1,19 +1,19 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -21,8 +21,8 @@ #include "btchip_bagl_extensions.h" #include "ui_pubkey.h" -#define P1_NO_DISPLAY 0x00 -#define P1_DISPLAY 0x01 +#define P1_NO_DISPLAY 0x00 +#define P1_DISPLAY 0x01 #define P1_REQUEST_TOKEN 0x02 #define P2_LEGACY 0x00 @@ -35,40 +35,38 @@ unsigned short btchip_apdu_get_wallet_public_key() { uint32_t request_token; unsigned char chainCode[32]; bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY); - bool display_request_token = N_btchip.pubKeyRequestRestriction && - (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && - G_io_apdu_media == IO_APDU_MEDIA_U2F; - bool require_user_approval = N_btchip.pubKeyRequestRestriction && - !(display_request_token || display) && - G_io_apdu_media == IO_APDU_MEDIA_U2F; + bool display_request_token = N_btchip.pubKeyRequestRestriction && (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && G_io_apdu_media == IO_APDU_MEDIA_U2F; + bool require_user_approval = N_btchip.pubKeyRequestRestriction && !(display_request_token || display) && G_io_apdu_media == IO_APDU_MEDIA_U2F; + switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { - case P1_NO_DISPLAY: - case P1_DISPLAY: - case P1_REQUEST_TOKEN: - break; - default: - return BTCHIP_SW_INCORRECT_P1_P2; + case P1_NO_DISPLAY: + case P1_DISPLAY: + case P1_REQUEST_TOKEN: + break; + default: + return BTCHIP_SW_INCORRECT_P1_P2; } switch (G_io_apdu_buffer[ISO_OFFSET_P2]) { - case P2_LEGACY: - break; - default: - return BTCHIP_SW_INCORRECT_P1_P2; + case P2_LEGACY: + break; + default: + return BTCHIP_SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_LC] < 0x01) { return BTCHIP_SW_INCORRECT_LENGTH; } - os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); + os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, + MAX_BIP32_PATH_LENGTH); - if (display_request_token) { - uint8_t request_token_offset = - ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA] * 4 + 1; + if(display_request_token){ + uint8_t request_token_offset = ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA]*4 + 1; request_token = btchip_read_u32(G_io_apdu_buffer + request_token_offset, true, false); } + if (os_global_pin_is_validated() != BOLOS_UX_OK) { return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; } @@ -84,14 +82,14 @@ unsigned short btchip_apdu_get_wallet_public_key() { keyLength = 33; } - os_memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, sizeof(btchip_public_key_D.W)); + os_memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, + sizeof(btchip_public_key_D.W)); - keyLength = btchip_public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - G_io_apdu_buffer + 67, // OUT - 150, // MAXOUTLEN - btchip_context_D.payToAddressVersion, - 0); + keyLength = btchip_public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN + keyLength, // INLEN + G_io_apdu_buffer + 67, // OUT + 150, // MAXOUTLEN + btchip_context_D.payToAddressVersion, 0); G_io_apdu_buffer[66] = keyLength; PRINTF("Length %d\n", keyLength); @@ -101,7 +99,8 @@ unsigned short btchip_apdu_get_wallet_public_key() { } // output chain code - os_memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, sizeof(chainCode)); + os_memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, + sizeof(chainCode)); btchip_context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); if (display) { @@ -112,12 +111,11 @@ unsigned short btchip_apdu_get_wallet_public_key() { os_memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); G_io_apdu_buffer[200 + keyLength] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_display_public_key(keyPath); - } - // If the token requested has already been approved in a previous call, the source is trusted so - // don't ask for approval again - else if (display_request_token && (!btchip_context_D.has_valid_token || - os_memcmp(&request_token, btchip_context_D.last_token, 4))) { + ui_display_public_key(keyPath); + } + // If the token requested has already been approved in a previous call, the source is trusted so don't ask for approval again + else if(display_request_token && + (!btchip_context_D.has_valid_token || os_memcmp(&request_token, btchip_context_D.last_token, 4))) { // disable the has_valid_token flag and store the new token btchip_context_D.has_valid_token = false; os_memcpy(btchip_context_D.last_token, &request_token, 4); @@ -125,10 +123,11 @@ unsigned short btchip_apdu_get_wallet_public_key() { snprintf(G_io_apdu_buffer + 200, 9, "%08X", request_token); G_io_apdu_buffer[200 + 8] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_display_token(); - } else if (require_user_approval) { + ui_display_token(); + } + else if(require_user_approval) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_request_pubkey_approval(); + ui_display_request_pubkey_approval(); } return BTCHIP_SW_OK; @@ -138,7 +137,8 @@ void btchip_bagl_user_action_display(unsigned char confirming) { unsigned short sw = BTCHIP_SW_OK; // confirm and finish the apdu exchange //spaghetti if (confirming) { - btchip_context_D.outLength -= 2; // status was already set by the last call + btchip_context_D.outLength -= + 2; // status was already set by the last call } else { sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; diff --git a/src/ui/pubkey/ui_pubkey.h b/src/ui/pubkey/ui_pubkey.h index da0f52f..a110b0c 100644 --- a/src/ui/pubkey/ui_pubkey.h +++ b/src/ui/pubkey/ui_pubkey.h @@ -16,6 +16,6 @@ ********************************************************************************/ #pragma once -void btchip_bagl_display_public_key(unsigned char* derivation_path); -void btchip_bagl_request_pubkey_approval(void); -void btchip_bagl_display_token(void); +void ui_display_public_key(unsigned char* derivation_path); +void ui_display_request_pubkey_approval(void); +void ui_display_token(void); diff --git a/src/ui/pubkey/ui_pubkey_bagl.c b/src/ui/pubkey/ui_pubkey_bagl.c index e01ab7a..4b4dc91 100644 --- a/src/ui/pubkey/ui_pubkey_bagl.c +++ b/src/ui/pubkey/ui_pubkey_bagl.c @@ -319,7 +319,7 @@ UX_FLOW(ux_display_token_flow, #endif -void btchip_bagl_display_public_key(unsigned char* derivation_path) { +void ui_display_public_key(unsigned char* derivation_path) { // append a white space at the end of the address to avoid glitch on nano S strcat(G_io_apdu_buffer + 200, " "); @@ -338,7 +338,7 @@ void btchip_bagl_display_public_key(unsigned char* derivation_path) { #endif // TARGET_NANOX } -void btchip_bagl_request_pubkey_approval(void) +void ui_display_request_pubkey_approval(void) { #if defined(TARGET_NANOS) // append and prepend a white space to the address @@ -350,7 +350,7 @@ void btchip_bagl_request_pubkey_approval(void) #endif // #if TARGET_ID } -void btchip_bagl_display_token(void) +void ui_display_token(void) { #if defined(TARGET_NANOS) ux_step = 0; diff --git a/src/ui/pubkey/ui_pubkey_nbgl.c b/src/ui/pubkey/ui_pubkey_nbgl.c index e88747d..ee8a543 100644 --- a/src/ui/pubkey/ui_pubkey_nbgl.c +++ b/src/ui/pubkey/ui_pubkey_nbgl.c @@ -89,7 +89,7 @@ static void warningChoiceClbk(bool reject) { } } -void btchip_bagl_display_public_key(unsigned char* derivation_path) { +void ui_display_public_key(unsigned char* derivation_path) { display_type = DISPLAY_ADDRESS; bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); @@ -108,13 +108,13 @@ void btchip_bagl_display_public_key(unsigned char* derivation_path) { } } -void btchip_bagl_request_pubkey_approval(void) +void ui_display_request_pubkey_approval(void) { display_type = EXPORT_REQUEST; nbgl_useCaseChoice("Export public key ?",NULL,"Export","Cancel",confirmationChoiceClbk); } -void btchip_bagl_display_token(void) +void ui_display_token(void) { display_type = DISPLAY_TOKEN; explicit_bzero(choice_text, sizeof(choice_text)); From b5d24eb9b373a8cb67ce3b5a5bb7bdeb6b06c062 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 28 Nov 2022 17:57:49 +0100 Subject: [PATCH 11/41] Clean-up : - Remove deprecated function calls, - Use "UNUSED" macro for unused function params, - Remove unused variables, - Remove Blue specific structs fields init, - Cast pointer to proper type to avoid warning. --- src/btchip.c | 60 +- src/btchip_apdu_get_coin_version.c | 38 +- src/btchip_apdu_get_trusted_input.c | 71 +- src/btchip_apdu_get_wallet_public_key.c | 14 +- src/btchip_apdu_hash_input_finalize_full.c | 379 +++++---- src/btchip_apdu_hash_input_start.c | 53 +- src/btchip_apdu_hash_sign.c | 72 +- src/btchip_apdu_sign_message.c | 176 ++-- src/btchip_base58.c | 219 +++-- src/btchip_context.c | 71 +- src/btchip_helpers.c | 219 +++-- src/btchip_transaction.c | 927 +++++++++++---------- src/main.c | 3 +- src/ui/pubkey/ui_pubkey_bagl.c | 5 +- src/ui/ui_shared.h | 10 +- 15 files changed, 1181 insertions(+), 1136 deletions(-) diff --git a/src/btchip.c b/src/btchip.c index be29262..c76db8d 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -1,19 +1,19 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "os.h" @@ -46,7 +46,8 @@ void app_dispatch(void) { cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; ins = G_io_apdu_buffer[ISO_OFFSET_INS]; for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { - if ((cla == DISPATCHER_CLA[dispatched]) && (ins == DISPATCHER_INS[dispatched])) { + if ((cla == DISPATCHER_CLA[dispatched]) && + (ins == DISPATCHER_INS[dispatched])) { break; } } @@ -55,7 +56,8 @@ void app_dispatch(void) { goto sendSW; } if (DISPATCHER_DATA_IN[dispatched]) { - if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || btchip_context_D.inLength - 5 == 0) { + if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || + btchip_context_D.inLength - 5 == 0) { btchip_context_D.sw = BTCHIP_SW_INCORRECT_LENGTH; goto sendSW; } @@ -63,19 +65,21 @@ void app_dispatch(void) { // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); } // call the apdu handler - btchip_context_D.sw = - ((apduProcessingFunction) PIC(DISPATCHER_FUNCTIONS[dispatched]))(); + btchip_context_D.sw = ((apduProcessingFunction)PIC( + DISPATCHER_FUNCTIONS[dispatched]))(); // an APDU has been replied. request for power off time extension from the // common ux #ifdef IO_APP_ACTIVITY IO_APP_ACTIVITY(); -#endif // IO_APP_ACTIVITY +#endif // IO_APP_ACTIVITY sendSW: // prepare SW after replied data - G_io_apdu_buffer[btchip_context_D.outLength] = (btchip_context_D.sw >> 8); - G_io_apdu_buffer[btchip_context_D.outLength + 1] = (btchip_context_D.sw & 0xff); + G_io_apdu_buffer[btchip_context_D.outLength] = + (btchip_context_D.sw >> 8); + G_io_apdu_buffer[btchip_context_D.outLength + 1] = + (btchip_context_D.sw & 0xff); btchip_context_D.outLength += 2; } CATCH(EXCEPTION_IO_RESET) { @@ -95,7 +99,7 @@ void app_dispatch(void) { } void app_main(void) { - os_memset(G_io_apdu_buffer, 0, 255); // paranoia + explicit_bzero(G_io_apdu_buffer, 255); // paranoia // Process the incoming APDUs @@ -103,12 +107,14 @@ void app_main(void) { btchip_context_D.outLength = 0; btchip_context_D.io_flags = 0; for (;;) { - // os_memset(G_io_apdu_buffer, 0, 255); // paranoia + + // explicit_bzero(G_io_apdu_buffer, 255); // paranoia // receive the whole apdu using the 7 bytes headers (ledger transport) - btchip_context_D.inLength = io_exchange(CHANNEL_APDU | btchip_context_D.io_flags, - // use the previous outlength as the reply - btchip_context_D.outLength); + btchip_context_D.inLength = + io_exchange(CHANNEL_APDU | btchip_context_D.io_flags, + // use the previous outlength as the reply + btchip_context_D.outLength); app_dispatch(); diff --git a/src/btchip_apdu_get_coin_version.c b/src/btchip_apdu_get_coin_version.c index 2113a20..c717a65 100644 --- a/src/btchip_apdu_get_coin_version.c +++ b/src/btchip_apdu_get_coin_version.c @@ -1,24 +1,24 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -#define P1_VERSION_ONLY 0x00 +#define P1_VERSION_ONLY 0x00 #define P1_VERSION_COINID 0x01 unsigned short btchip_apdu_get_coin_version() { @@ -30,11 +30,11 @@ unsigned short btchip_apdu_get_coin_version() { G_io_apdu_buffer[offset++] = btchip_context_D.payToScriptHashVersion; G_io_apdu_buffer[offset++] = btchip_context_D.coinFamily; G_io_apdu_buffer[offset++] = btchip_context_D.coinIdLength; - os_memmove(G_io_apdu_buffer + offset, btchip_context_D.coinId, btchip_context_D.coinIdLength); + memmove(G_io_apdu_buffer + offset, btchip_context_D.coinId, + btchip_context_D.coinIdLength); offset += btchip_context_D.coinIdLength; G_io_apdu_buffer[offset++] = btchip_context_D.shortCoinIdLength; - os_memmove(G_io_apdu_buffer + offset, - btchip_context_D.shortCoinId, + memmove(G_io_apdu_buffer + offset, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); offset += btchip_context_D.shortCoinIdLength; btchip_context_D.outLength = offset; diff --git a/src/btchip_apdu_get_trusted_input.c b/src/btchip_apdu_get_trusted_input.c index ab9e975..b985adf 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/btchip_apdu_get_trusted_input.c @@ -1,25 +1,25 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 -#define GET_TRUSTED_INPUT_P1_NEXT 0x80 +#define GET_TRUSTED_INPUT_P1_NEXT 0x80 #define TRUSTEDINPUT_SIZE 48 @@ -27,42 +27,46 @@ unsigned short btchip_apdu_get_trusted_input() { unsigned char apduLength; unsigned char dataOffset = 0; unsigned char trustedInputSignature[32]; - cx_sha256_t hash; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; + if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize btchip_context_D.transactionTargetInput = btchip_read_u32(G_io_apdu_buffer + ISO_OFFSET_CDATA, 1, 0); - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; btchip_context_D.trustedInputProcessed = 0; btchip_context_D.transactionContext.consumeP2SH = 0; btchip_set_check_internal_structure_integrity(1); dataOffset = 4; btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; - } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { + } + else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { return BTCHIP_SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00) { return BTCHIP_SW_INCORRECT_P1_P2; } - btchip_context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; + btchip_context_D.transactionBufferPointer = + G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; btchip_context_D.transactionDataRemaining = apduLength - dataOffset; transaction_parse(PARSE_MODE_TRUSTED_INPUT); if (btchip_context_D.transactionContext.transactionState == BTCHIP_TRANSACTION_PARSED) { - // unsigned char targetHash[32]; + //unsigned char targetHash[32]; - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); if (!btchip_context_D.trustedInputProcessed) { // Output was not found return BTCHIP_SW_INCORRECT_DATA; } - // cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, + //cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, // (unsigned char *)NULL, 0, targetHash); // Otherwise prepare @@ -71,21 +75,18 @@ unsigned short btchip_apdu_get_trusted_input() { G_io_apdu_buffer[1] = 0x00; blake256_Final(&btchip_context_D.transactionHashPrefix, G_io_apdu_buffer + 4); - // cx_hash(&btchip_context_D.transactionHashPrefix, CX_LAST, (unsigned char *)NULL, 0, - // G_io_apdu_buffer + 4); + //cx_hash(&btchip_context_D.transactionHashPrefix, CX_LAST, (unsigned char *)NULL, 0, G_io_apdu_buffer + 4); - btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, btchip_context_D.transactionTargetInput); - os_memmove(G_io_apdu_buffer + 4 + 32 + 4, - btchip_context_D.transactionContext.transactionAmount, - 8); + btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, + btchip_context_D.transactionTargetInput); + memmove(G_io_apdu_buffer + 4 + 32 + 4, + btchip_context_D.transactionContext.transactionAmount, 8); cx_hmac_sha256(N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), - G_io_apdu_buffer, - TRUSTEDINPUT_SIZE, - trustedInputSignature, - 32); - os_memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, 8); + sizeof(N_btchip.bkp.trustedinput_key), G_io_apdu_buffer, + TRUSTEDINPUT_SIZE, trustedInputSignature, 32); + memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, + 8); btchip_context_D.outLength = 0x38; } diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 540286d..b4e2d56 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -58,7 +58,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { if (G_io_apdu_buffer[ISO_OFFSET_LC] < 0x01) { return BTCHIP_SW_INCORRECT_LENGTH; } - os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, + memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); if(display_request_token){ @@ -82,7 +82,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { keyLength = 33; } - os_memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, + memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, sizeof(btchip_public_key_D.W)); keyLength = btchip_public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN @@ -99,7 +99,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { } // output chain code - os_memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, + memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, sizeof(chainCode)); btchip_context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); @@ -108,19 +108,19 @@ unsigned short btchip_apdu_get_wallet_public_key() { return BTCHIP_SW_INCORRECT_DATA; } // Hax, avoid wasting space - os_memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); + memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); G_io_apdu_buffer[200 + keyLength] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; ui_display_public_key(keyPath); } // If the token requested has already been approved in a previous call, the source is trusted so don't ask for approval again else if(display_request_token && - (!btchip_context_D.has_valid_token || os_memcmp(&request_token, btchip_context_D.last_token, 4))) { + (!btchip_context_D.has_valid_token || memcmp(&request_token, btchip_context_D.last_token, 4))) { // disable the has_valid_token flag and store the new token btchip_context_D.has_valid_token = false; - os_memcpy(btchip_context_D.last_token, &request_token, 4); + memcpy(btchip_context_D.last_token, &request_token, 4); // Hax, avoid wasting space - snprintf(G_io_apdu_buffer + 200, 9, "%08X", request_token); + snprintf((char*)G_io_apdu_buffer + 200, 9, "%08X", request_token); G_io_apdu_buffer[200 + 8] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; ui_display_token(); diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 474d229..e4c7187 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -1,19 +1,19 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ // TODO Trustlet, BAGL : process each output separately. // review nvm_write policy @@ -22,11 +22,11 @@ #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" -#define FINALIZE_P1_MORE 0x00 -#define FINALIZE_P1_LAST 0x80 +#define FINALIZE_P1_MORE 0x00 +#define FINALIZE_P1_LAST 0x80 #define FINALIZE_P1_CHANGEINFO 0xFF -#define FLAG_SIGNATURE 0x01 +#define FLAG_SIGNATURE 0x01 #define FLAG_CHANGE_VALIDATED 0x80 extern uint8_t prepare_full_output(uint8_t checkOnly); @@ -34,7 +34,8 @@ extern uint8_t prepare_full_output(uint8_t checkOnly); static void btchip_apdu_hash_input_finalize_full_reset(void) { btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - os_memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); + explicit_bzero(btchip_context_D.totalOutputAmount, + sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; btchip_set_check_internal_structure_integrity(1); } @@ -42,7 +43,7 @@ static void btchip_apdu_hash_input_finalize_full_reset(void) { static bool check_output_displayable() { PRINTF("Check if output is displayable\n"); bool displayable = true; - unsigned char amount[8], isOpReturn, isP2sh, j, nullAmount = 1; + unsigned char amount[8], isOpReturn, isP2sh, j,nullAmount = 1; unsigned char isOpCreate, isOpCall; for (j = 0; j < 8; j++) { @@ -54,27 +55,30 @@ static bool check_output_displayable() { if (!nullAmount) { btchip_swap_bytes(amount, btchip_context_D.currentOutput, 8); transaction_amount_add_be(btchip_context_D.totalOutputAmount, - btchip_context_D.totalOutputAmount, - amount); + btchip_context_D.totalOutputAmount, amount); } - isOpReturn = btchip_output_script_is_op_return( - btchip_context_D.currentOutput + 8 + 2); // +2 for script version, decred particularity + isOpReturn = + btchip_output_script_is_op_return(btchip_context_D.currentOutput + 8 + 2); // +2 for script version, decred particularity isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + 8 + 2); - isOpCreate = btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); - isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); + isOpCreate = + btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); + isOpCall = + btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); - if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8 + 2) && !isP2sh && - !(nullAmount && isOpReturn)) { + if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8 + 2) && + !isP2sh && !(nullAmount && isOpReturn)) { PRINTF("Error: Unrecognized input script\n"); THROW(EXCEPTION); } if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { bool changeFound = false; unsigned char addressOffset = - (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (!isP2sh && os_memcmp(btchip_context_D.currentOutput + 8 + 2 + addressOffset, - btchip_context_D.tmpCtx.output.changeAddress + 1, - 20) == 0) { + (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH + : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (!isP2sh && + memcmp(btchip_context_D.currentOutput + 8 + 2 + addressOffset, + btchip_context_D.tmpCtx.output.changeAddress + 1, + 20) == 0) { changeFound = true; } @@ -96,94 +100,97 @@ static bool handle_output_state() { btchip_context_D.discardSize = 0; bool processed = false; switch (btchip_context_D.outputParsingState) { - case BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS: { - // this is default init state - btchip_context_D.totalOutputs = 0; - if (btchip_context_D.currentOutputOffset < 1) { - break; - } - if (btchip_context_D.currentOutput[0] < 0xFD) { - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_context_D.currentOutput[0]; - discardSize = 1; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; + case BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS: { + // this is default init state + btchip_context_D.totalOutputs = 0; + if (btchip_context_D.currentOutputOffset < 1) { + break; + } + if (btchip_context_D.currentOutput[0] < 0xFD) { + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + btchip_context_D.currentOutput[0]; + discardSize = 1; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } + if (btchip_context_D.currentOutput[0] == 0xFD) { + if (btchip_context_D.currentOutputOffset < 3) { break; } - if (btchip_context_D.currentOutput[0] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 3) { - break; - } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - (btchip_context_D.currentOutput[2] << 8) | btchip_context_D.currentOutput[1]; - discardSize = 3; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else if (btchip_context_D.currentOutput[0] == 0xFE) { - if (btchip_context_D.currentOutputOffset < 5) { - break; - } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_read_u32(btchip_context_D.currentOutput + 1, 0, 0); - discardSize = 5; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + (btchip_context_D.currentOutput[2] << 8) | + btchip_context_D.currentOutput[1]; + discardSize = 3; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else if (btchip_context_D.currentOutput[0] == 0xFE) { + if (btchip_context_D.currentOutputOffset < 5) { break; - } else { - THROW(EXCEPTION); } - } break; + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + btchip_read_u32(btchip_context_D.currentOutput + 1, 0, 0); + discardSize = 5; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else { + THROW(EXCEPTION); + } + } break; - case BTCHIP_OUTPUT_PARSING_OUTPUT: { - PRINTF("BTCHIP_OUTPUT_PARSING_OUTPUT:\n"); + case BTCHIP_OUTPUT_PARSING_OUTPUT: { + PRINTF("BTCHIP_OUTPUT_PARSING_OUTPUT:\n"); - unsigned int scriptSize; - if (btchip_context_D.currentOutputOffset < 9) { - break; - } - if (btchip_context_D.currentOutput[8 + 2] < 0xFD) { - scriptSize = btchip_context_D.currentOutput[8 + 2]; - discardSize = 1; - } else if (btchip_context_D.currentOutput[8 + 2] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 9 + 2) { - break; - } - scriptSize = btchip_read_u32(btchip_context_D.currentOutput + 9, 0, 0); - discardSize = 3; - } else { - // Unrealistically large script - THROW(EXCEPTION); - } - if (btchip_context_D.currentOutputOffset < 8 + 2 + discardSize + scriptSize) { - discardSize = 0; + unsigned int scriptSize; + if (btchip_context_D.currentOutputOffset < 9) { + break; + } + if (btchip_context_D.currentOutput[8+2] < 0xFD) { + scriptSize = btchip_context_D.currentOutput[8+2]; + discardSize = 1; + } else if (btchip_context_D.currentOutput[8+2] == 0xFD) { + if (btchip_context_D.currentOutputOffset < 9 + 2) { break; } + scriptSize = + btchip_read_u32(btchip_context_D.currentOutput + 9, 0, 0); + discardSize = 3; + } else { + // Unrealistically large script + THROW(EXCEPTION); + } + if (btchip_context_D.currentOutputOffset < + 8 + 2 + discardSize + scriptSize) { + discardSize = 0; + break; + } - processed = true; + processed = true; - discardSize += 8 + 2 + scriptSize; + discardSize += 8 + 2 + scriptSize; - if (check_output_displayable()) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; + if (check_output_displayable()) { + btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - // The output can be processed by the UI + // The output can be processed by the UI - btchip_context_D.discardSize = discardSize; - discardSize = 0; - } else { - btchip_context_D.remainingOutputs--; - PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); - } - } break; + btchip_context_D.discardSize = discardSize; + discardSize = 0; + } else { + btchip_context_D.remainingOutputs--; + PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); + } + } break; - default: - THROW(EXCEPTION); + default: + THROW(EXCEPTION); } if (discardSize != 0) { PRINTF("discard %d bytes from output\n", discardSize); - os_memmove(btchip_context_D.currentOutput, + memmove(btchip_context_D.currentOutput, btchip_context_D.currentOutput + discardSize, btchip_context_D.currentOutputOffset - discardSize); btchip_context_D.currentOutputOffset -= discardSize; @@ -201,17 +208,13 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( unsigned char apduLength; unsigned short sw = BTCHIP_SW_OK; unsigned char *target = G_io_apdu_buffer; - unsigned char keycardActivated = 0; - unsigned char screenPaired = 0; - unsigned char deepControl = 0; unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; - unsigned char persistentCommit = 0; unsigned char hashOffset = 0; - unsigned char numOutputs = 0; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && (p1 != FINALIZE_P1_CHANGEINFO)) { + if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && + (p1 != FINALIZE_P1_CHANGEINFO)) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -238,39 +241,42 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } - os_memset(transactionSummary, 0, sizeof(btchip_transaction_summary_t)); + explicit_bzero(transactionSummary, + sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { // Called with no change path, abort, should be prevented on // the client side goto return_OK; } - os_memmove(transactionSummary->summarydata.keyPath, + memmove(transactionSummary->summarydata.keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); - btchip_private_derive_keypair(transactionSummary->summarydata.keyPath, 1, NULL); - if (((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { + btchip_private_derive_keypair( + transactionSummary->summarydata.keyPath, 1, NULL); + if (((N_btchip.bkp.config.options & + BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { keyLength = 65; } else { btchip_compress_public_key_value(btchip_public_key_D.W); keyLength = 33; } - btchip_public_key_hash160(btchip_public_key_D.W, // IN - keyLength, // INLEN - transactionSummary->summarydata.changeAddress + 1 // OUT + btchip_public_key_hash160( + btchip_public_key_D.W, // IN + keyLength, // INLEN + transactionSummary->summarydata.changeAddress + 1 // OUT ); - os_memmove(btchip_context_D.tmpCtx.output.changeAddress, - transactionSummary->summarydata.changeAddress, - sizeof(transactionSummary->summarydata.changeAddress)); + memmove( + btchip_context_D.tmpCtx.output.changeAddress, + transactionSummary->summarydata.changeAddress, + sizeof(transactionSummary->summarydata.changeAddress)); btchip_context_D.tmpCtx.output.changeInitialized = 1; btchip_context_D.tmpCtx.output.changeAccepted = 0; - // if the bip44 change path provided is not canonical or its index are unsual, ask - // for user approval - if (bip44_derivation_guard(transactionSummary->summarydata.keyPath, true)) { + // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval + if(bip44_derivation_guard(transactionSummary->summarydata.keyPath, true)) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_context_D.outputParsingState = BTCHIP_BIP44_CHANGE_PATH_VALIDATION; - btchip_bagl_request_change_path_approval( - transactionSummary->summarydata.keyPath); + btchip_bagl_request_change_path_approval(transactionSummary->summarydata.keyPath); } goto return_OK; @@ -279,15 +285,10 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( // Always update the transaction & authorization hashes with the // given data - PRINTF("Adding to prefix hash:\n%.*H\n", - apduLength - hashOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); - blake256_Update(&btchip_context_D.transactionHashPrefix, - G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, - apduLength - hashOffset); - blake256_Update(&btchip_context_D.transactionHashAuthorization, - G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, - apduLength - hashOffset); + PRINTF("Adding to prefix hash:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); + blake256_Update(&btchip_context_D.transactionHashPrefix, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset); + blake256_Update(&btchip_context_D.transactionHashAuthorization, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset); + if (btchip_context_D.transactionContext.firstSigned) { if ((btchip_context_D.currentOutputOffset + apduLength) > @@ -296,21 +297,23 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_INCORRECT_DATA; goto discardTransaction; } - os_memmove(btchip_context_D.currentOutput + btchip_context_D.currentOutputOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA, - apduLength); + memmove(btchip_context_D.currentOutput + + btchip_context_D.currentOutputOffset, + G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); btchip_context_D.currentOutputOffset += apduLength; // Check if the legacy UI can be applied if ((G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_LAST) && - !btchip_context_D.tmpCtx.output.multipleOutput && prepare_full_output(1)) { + !btchip_context_D.tmpCtx.output.multipleOutput && + prepare_full_output(1)) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_HANDLE_LEGACY; + btchip_context_D.outputParsingState = + BTCHIP_OUTPUT_HANDLE_LEGACY; btchip_context_D.remainingOutputs = 0; } else { // parse outputs until one can be displayed while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) ; // Finalize the TX if necessary @@ -318,7 +321,8 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( if ((btchip_context_D.remainingOutputs == 0) && (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; + btchip_context_D.outputParsingState = + BTCHIP_OUTPUT_FINALIZE_TX; } } } @@ -335,12 +339,15 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( blake256_Final(&btchip_context_D.transactionHashAuthorization, authorizationHash); - if (btchip_context_D.transactionContext.firstSigned) { + + if(btchip_context_D.transactionContext.firstSigned) { if (!btchip_context_D.tmpCtx.output.changeInitialized) { - os_memset(transactionSummary, 0, sizeof(btchip_transaction_summary_t)); + explicit_bzero(transactionSummary, + sizeof(btchip_transaction_summary_t)); } - transactionSummary->payToAddressVersion = btchip_context_D.payToAddressVersion; + transactionSummary->payToAddressVersion = + btchip_context_D.payToAddressVersion; transactionSummary->payToScriptHashVersion = btchip_context_D.payToScriptHashVersion; @@ -362,36 +369,39 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( // (this is done to keep the transaction counter limit per session // synchronized) if (btchip_context_D.transactionContext.firstSigned) { - os_memmove(transactionSummary->authorizationHash, + memmove(transactionSummary->authorizationHash, authorizationHash, sizeof(transactionSummary->authorizationHash)); - goto return_OK; + goto return_OK; } else { - if (btchip_secure_memcmp(authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { + if (btchip_secure_memcmp( + authorizationHash, + transactionSummary->authorizationHash, + sizeof(transactionSummary->authorizationHash))) { PRINTF("Authorization hash doesn't match the previous one\n"); sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - discardTransaction: +discardTransaction: CLOSE_TRY; goto catch_discardTransaction; - } else { + } + else { PRINTF("Authorization Hash OK:\n%.*H\n", 32, authorizationHash); } } - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_SIGN_READY; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_SIGN_READY; sw = BTCHIP_SW_OK; } CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0x0F); catch_discardTransaction: - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; - os_memmove(G_io_apdu_buffer, - btchip_context_D.currentOutput, + memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, btchip_context_D.currentOutputOffset); btchip_context_D.outLength = btchip_context_D.currentOutputOffset; } @@ -405,28 +415,32 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( unsigned short btchip_apdu_hash_input_finalize_full() { PRINTF("state=%d\n", btchip_context_D.outputParsingState); - unsigned short sw = - btchip_apdu_hash_input_finalize_full_internal(&btchip_context_D.transactionSummary); + unsigned short sw = btchip_apdu_hash_input_finalize_full_internal( + &btchip_context_D.transactionSummary); if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { // if the UI reject the processing of the request, then reply // immediately bool status; - if (btchip_context_D.outputParsingState == BTCHIP_BIP44_CHANGE_PATH_VALIDATION) { + if(btchip_context_D.outputParsingState == BTCHIP_BIP44_CHANGE_PATH_VALIDATION) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; return sw; - } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { + } + else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { PRINTF("BAGL finalize tx:\n"); status = btchip_bagl_finalize_tx(); - } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_HANDLE_LEGACY) { + } else if (btchip_context_D.outputParsingState == + BTCHIP_OUTPUT_HANDLE_LEGACY) { PRINTF("BAGL confirm output legacy:\n"); status = btchip_bagl_confirm_full_output(); - } else { + } + else { PRINTF("BAGL confirm single output:\n"); status = btchip_bagl_confirm_single_output(); } if (!status) { btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; sw = BTCHIP_SW_INCORRECT_DATA; } @@ -441,22 +455,28 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { if (confirming) { // Check if all inputs have been confirmed - if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_PARSING_OUTPUT) { + if (btchip_context_D.outputParsingState == + BTCHIP_OUTPUT_PARSING_OUTPUT) { btchip_context_D.remainingOutputs--; PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); } while (btchip_context_D.remainingOutputs != 0) { - os_memmove(btchip_context_D.currentOutput, - btchip_context_D.currentOutput + btchip_context_D.discardSize, - btchip_context_D.currentOutputOffset - btchip_context_D.discardSize); - btchip_context_D.currentOutputOffset -= btchip_context_D.discardSize; + memmove(btchip_context_D.currentOutput, + btchip_context_D.currentOutput + + btchip_context_D.discardSize, + btchip_context_D.currentOutputOffset - + btchip_context_D.discardSize); + btchip_context_D.currentOutputOffset -= + btchip_context_D.discardSize; btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + while (handle_output_state() && + (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) ; if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { if (!btchip_bagl_confirm_single_output()) { - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_INCORRECT_DATA; break; } else { @@ -469,12 +489,15 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { } } - if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_PARSING_OUTPUT) && + if ((btchip_context_D.outputParsingState == + BTCHIP_OUTPUT_PARSING_OUTPUT) && (btchip_context_D.remainingOutputs == 0)) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; if (!btchip_bagl_finalize_tx()) { - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NONE; - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.outputParsingState = + BTCHIP_OUTPUT_PARSING_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_INCORRECT_DATA; } else { // Let the UI play @@ -482,16 +505,22 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { } } - if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) || - (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_HANDLE_LEGACY)) { + if ((btchip_context_D.outputParsingState == + BTCHIP_OUTPUT_FINALIZE_TX) || + (btchip_context_D.outputParsingState == + BTCHIP_OUTPUT_HANDLE_LEGACY)) { btchip_context_D.transactionContext.firstSigned = 0; - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_SIGN_READY; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_SIGN_READY; + } - btchip_context_D.outLength -= 2; // status was already set by the last call + btchip_context_D.outLength -= + 2; // status was already set by the last call } else { // Discard transaction - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; btchip_context_D.outLength = 0; } diff --git a/src/btchip_apdu_hash_input_start.c b/src/btchip_apdu_hash_input_start.c index f2fcc82..9b16a26 100644 --- a/src/btchip_apdu_hash_input_start.c +++ b/src/btchip_apdu_hash_input_start.c @@ -1,40 +1,44 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -#define P1_FIRST 0x00 -#define P1_NEXT 0x80 -#define P2_NEW 0x00 +#define P1_FIRST 0x00 +#define P1_NEXT 0x80 +#define P2_NEW 0x00 #define P2_CONTINUE 0x80 + unsigned short btchip_apdu_hash_input_start() { unsigned char apduLength; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; PRINTF("\n### HASH_INPUT_START:\n"); + if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { // Initialize - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; - } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { + } + else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -58,14 +62,17 @@ unsigned short btchip_apdu_hash_input_start() { btchip_context_D.transactionContext.relaxed = 0; btchip_set_check_internal_structure_integrity(1); // Initialize for screen pairing - os_memset(&btchip_context_D.tmpCtx.output, 0, sizeof(btchip_context_D.tmpCtx.output)); + explicit_bzero(&btchip_context_D.tmpCtx.output, + sizeof(btchip_context_D.tmpCtx.output)); btchip_context_D.tmpCtx.output.changeAccepted = 1; } - } else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { + } + else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { return BTCHIP_SW_INCORRECT_P1_P2; } - btchip_context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA; + btchip_context_D.transactionBufferPointer = + G_io_apdu_buffer + ISO_OFFSET_CDATA; btchip_context_D.transactionDataRemaining = apduLength; transaction_parse(PARSE_MODE_SIGNATURE); diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 54ecb85..087a9f2 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -1,19 +1,19 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -21,6 +21,7 @@ #define SIGHASH_ALL 0x01 unsigned short btchip_apdu_hash_sign() { + PRINTF("\n### HASH_SIGN:\n"); unsigned long int lockTime; @@ -29,14 +30,12 @@ unsigned short btchip_apdu_hash_sign() { unsigned char dataBuffer[8]; unsigned char hash1[32]; unsigned char hash2[32]; - unsigned char authorizationLength; unsigned char *parameters = G_io_apdu_buffer + ISO_OFFSET_CDATA; - unsigned char *authorization; unsigned short sw; unsigned char keyPath[MAX_BIP32_PATH_LENGTH]; - cx_sha256_t localHash; - if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) && (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { + if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) && + (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -50,8 +49,7 @@ unsigned short btchip_apdu_hash_sign() { btchip_set_check_internal_structure_integrity(0); if (btchip_context_D.transactionContext.transactionState != BTCHIP_TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", - btchip_context_D.transactionContext.transactionState); + PRINTF("Invalid transaction state %d\n", btchip_context_D.transactionContext.transactionState); sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } @@ -63,7 +61,8 @@ unsigned short btchip_apdu_hash_sign() { CLOSE_TRY; goto catch_discardTransaction; } - os_memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); + memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, + MAX_BIP32_PATH_LENGTH); parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; lockTime = btchip_read_u32(parameters, 1, 0); @@ -73,7 +72,8 @@ unsigned short btchip_apdu_hash_sign() { sighashType = *(parameters++); PRINTF("SighashType: %d\n", sighashType); - if (((N_btchip.bkp.config.options & BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { + if (((N_btchip.bkp.config.options & + BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { // if bitcoin cash OR forkid is set, then use the fork id if (G_coin_config->forkid) { #define SIGHASH_FORKID 0x40 @@ -105,9 +105,8 @@ unsigned short btchip_apdu_hash_sign() { btchip_write_u32_le(dataBuffer + 4, expiry); PRINTF("Finalize hash with %.*H\n", sizeof(dataBuffer), dataBuffer); - blake256_Update(&btchip_context_D.transactionHashPrefix, - dataBuffer, - sizeof(dataBuffer)); + + blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, sizeof(dataBuffer)); blake256_Final(&btchip_context_D.transactionHashPrefix, hash1); PRINTF("Hash1 %.*H\n", sizeof(hash1), hash1); @@ -118,28 +117,26 @@ unsigned short btchip_apdu_hash_sign() { btchip_write_u32_le(dataBuffer, sighashType); // include sighash type PRINTF("Sighash type: %.*H\n", 4, dataBuffer); - blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, 4); + blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, 4); // include prefix_hash PRINTF("Prefix hash: %.*H\n", sizeof(hash1), hash1); - blake256_Update(&btchip_context_D.transactionHashPrefix, hash1, sizeof(hash1)); + blake256_Update(&btchip_context_D.transactionHashPrefix, hash1, sizeof(hash1)); // include witness_hash PRINTF("Witness hash: %.*H\n", sizeof(hash2), hash2); - blake256_Update(&btchip_context_D.transactionHashPrefix, hash2, sizeof(hash2)); + blake256_Update(&btchip_context_D.transactionHashPrefix, hash2, sizeof(hash2)); // final signature hash blake256_Final(&btchip_context_D.transactionHashPrefix, hash2); PRINTF("Hash to sign: %.*H\n", sizeof(hash2), hash2); + // Sign PRINTF("Pub key: %.*H\n", sizeof(public_key_D.W), public_key_D.W); btchip_signverify_finalhash( - &btchip_private_key_D, - 1, - hash2, - sizeof(hash2), - G_io_apdu_buffer, - sizeof(G_io_apdu_buffer), - ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + &btchip_private_key_D, 1, hash2, sizeof(hash2), + G_io_apdu_buffer, sizeof(G_io_apdu_buffer), + ((N_btchip.bkp.config.options & + BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; G_io_apdu_buffer[btchip_context_D.outLength++] = sighashType; @@ -151,7 +148,8 @@ unsigned short btchip_apdu_hash_sign() { CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0xF); catch_discardTransaction: - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; } FINALLY { btchip_set_check_internal_structure_integrity(1); diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 6ac29ff..b74f2a8 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -1,33 +1,33 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" #define P1_PREPARE 0x00 -#define P1_SIGN 0x80 -#define P2_LEGACY 0x00 -#define P2_FIRST 0x01 -#define P2_OTHER 0x80 +#define P1_SIGN 0x80 +#define P2_LEGACY 0x00 +#define P2_FIRST 0x01 +#define P2_OTHER 0x80 -#define BITID_NONE 0 +#define BITID_NONE 0 #define BITID_POWERCYCLE 1 -#define BITID_MULTIPLE 2 +#define BITID_MULTIPLE 2 //#define SLIP_13 0x8000000D @@ -86,8 +86,7 @@ unsigned short btchip_apdu_sign_message_internal() { unsigned char chunkLength; unsigned char messageLength[3]; unsigned char messageLengthSize; - os_memset(&btchip_context_D.transactionSummary, - 0, + explicit_bzero(&btchip_context_D.transactionSummary, sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { PRINTF("Invalid path\n"); @@ -99,9 +98,9 @@ unsigned short btchip_apdu_sign_message_internal() { btchip_context_D.payToAddressVersion; btchip_context_D.transactionSummary.payToScriptHashVersion = btchip_context_D.payToScriptHashVersion; - os_memmove(btchip_context_D.transactionSummary.summarydata.keyPath, - G_io_apdu_buffer + offset, - MAX_BIP32_PATH_LENGTH); + memmove( + btchip_context_D.transactionSummary.summarydata.keyPath, + G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); offset += (4 * G_io_apdu_buffer[offset]) + 1; if (p2 == P2_LEGACY) { btchip_context_D.transactionSummary.messageLength = @@ -109,10 +108,12 @@ unsigned short btchip_apdu_sign_message_internal() { offset++; } else { btchip_context_D.transactionSummary.messageLength = - (G_io_apdu_buffer[offset] << 8) | (G_io_apdu_buffer[offset + 1]); + (G_io_apdu_buffer[offset] << 8) | + (G_io_apdu_buffer[offset + 1]); offset += 2; } - if (btchip_context_D.transactionSummary.messageLength == 0) { + if (btchip_context_D.transactionSummary.messageLength == + 0) { PRINTF("Null message length\n"); sw = BTCHIP_SW_INCORRECT_DATA; CLOSE_TRY; @@ -120,43 +121,35 @@ unsigned short btchip_apdu_sign_message_internal() { } btchip_context_D.hashedMessageLength = 0; cx_sha256_init(&btchip_context_D.transactionHashPrefix); - cx_sha256_init(&btchip_context_D.transactionHashWitness); - chunkLength = btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH; - cx_hash(&btchip_context_D.transactionHashPrefix.header, - 0, - &chunkLength, - 1, - NULL, - 0); - cx_hash(&btchip_context_D.transactionHashPrefix.header, - 0, + cx_sha256_init( + &btchip_context_D.transactionHashWitness); + chunkLength = + btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH; + cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + &chunkLength, 1, NULL, 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, btchip_context_D.coinId, - btchip_context_D.coinIdLength, - NULL, - 0); - cx_hash(&btchip_context_D.transactionHashPrefix.header, - 0, - (unsigned char *) SIGNMAGIC, - SIGNMAGIC_LENGTH, - NULL, - 0); - if (btchip_context_D.transactionSummary.messageLength < 0xfd) { - messageLength[0] = btchip_context_D.transactionSummary.messageLength; + btchip_context_D.coinIdLength, NULL, 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0); + if (btchip_context_D.transactionSummary.messageLength < + 0xfd) { + messageLength[0] = + btchip_context_D.transactionSummary.messageLength; messageLengthSize = 1; } else { messageLength[0] = 0xfd; messageLength[1] = - (btchip_context_D.transactionSummary.messageLength & 0xff); - messageLength[2] = - ((btchip_context_D.transactionSummary.messageLength >> 8) & 0xff); + (btchip_context_D.transactionSummary.messageLength & + 0xff); + messageLength[2] = ((btchip_context_D.transactionSummary + .messageLength >> + 8) & + 0xff); messageLengthSize = 3; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, - 0, - messageLength, - messageLengthSize, - NULL, - 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + messageLength, messageLengthSize, NULL, 0); chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); if ((btchip_context_D.hashedMessageLength + chunkLength) > btchip_context_D.transactionSummary.messageLength) { @@ -165,18 +158,11 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, - 0, - G_io_apdu_buffer + offset, - chunkLength, - NULL, - 0); - cx_hash(&btchip_context_D.transactionHashWitness.header, - 0, - G_io_apdu_buffer + offset, - chunkLength, - NULL, - 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + G_io_apdu_buffer + offset, chunkLength, NULL, 0); + cx_hash( + &btchip_context_D.transactionHashWitness.header, + 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0); btchip_context_D.hashedMessageLength += chunkLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -194,18 +180,11 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, - 0, - G_io_apdu_buffer + offset, - apduLength, - NULL, - 0); - cx_hash(&btchip_context_D.transactionHashWitness.header, - 0, - G_io_apdu_buffer + offset, - apduLength, - NULL, - 0); + cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + G_io_apdu_buffer + offset, apduLength, NULL, 0); + cx_hash( + &btchip_context_D.transactionHashWitness.header, + 0, G_io_apdu_buffer + offset, apduLength, NULL, 0); btchip_context_D.hashedMessageLength += apduLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -225,8 +204,8 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - if (checkBitId(btchip_context_D.transactionSummary.summarydata.keyPath) != - BITID_NONE) { + if (checkBitId(btchip_context_D.transactionSummary.summarydata + .keyPath) != BITID_NONE) { sw = btchip_compute_hash(); } else { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; @@ -239,7 +218,8 @@ unsigned short btchip_apdu_sign_message_internal() { sw = SW_TECHNICAL_DETAILS(0x0F); } discard : { - os_memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); + explicit_bzero(&btchip_context_D.transactionSummary, + sizeof(btchip_transaction_summary_t)); } FINALLY { return sw; @@ -262,28 +242,26 @@ unsigned short btchip_compute_hash() { btchip_context_D.outLength = 0; BEGIN_TRY { TRY { - cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, 0, hash, 32); + cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, + 0, hash, 32); cx_sha256_init(&btchip_context_D.transactionHashPrefix); - cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, 32, hash, 32); - btchip_private_derive_keypair(btchip_context_D.transactionSummary.summarydata.keyPath, - 0, - NULL); + cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, + 32, hash, 32); + btchip_private_derive_keypair( + btchip_context_D.transactionSummary.summarydata.keyPath, 0, + NULL); btchip_signverify_finalhash( - &btchip_private_key_D, - 1, - hash, - sizeof(hash), // IN - G_io_apdu_buffer, - 100, // OUT - ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + &btchip_private_key_D, 1, hash, sizeof(hash), // IN + G_io_apdu_buffer, 100, // OUT + ((N_btchip.bkp.config.options & + BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; } CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0x0F); } FINALLY { - os_memset(&btchip_context_D.transactionSummary, - 0, + explicit_bzero(&btchip_context_D.transactionSummary, sizeof(btchip_transaction_summary_t)); } } diff --git a/src/btchip_base58.c b/src/btchip_base58.c index 5577888..a93145d 100644 --- a/src/btchip_base58.c +++ b/src/btchip_base58.c @@ -1,135 +1,134 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #define MAX_DEC_INPUT_SIZE 164 #define MAX_ENC_INPUT_SIZE 120 -int btchip_decode_base58(const char *in, size_t length, unsigned char *out, size_t *outlen) { - unsigned char tmp[MAX_DEC_INPUT_SIZE]; - unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; - unsigned char i; - unsigned char j; - unsigned char startAt; - unsigned char zeroCount = 0; - if (length > MAX_DEC_INPUT_SIZE) { - return -1; +int btchip_decode_base58(const char *in, size_t length, + unsigned char *out, size_t *outlen) { + unsigned char tmp[MAX_DEC_INPUT_SIZE]; + unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; + unsigned char i; + unsigned char j; + unsigned char startAt; + unsigned char zeroCount = 0; + if (length > MAX_DEC_INPUT_SIZE) { + return -1; + } + memmove(tmp, in, length); + PRINTF("To decode\n%.*H\n",length,tmp); + for (i = 0; i < length; i++) { + if (in[i] >= sizeof(BASE58TABLE)) { + return -1; } - os_memmove(tmp, in, length); - PRINTF("To decode\n%.*H\n", length, tmp); - for (i = 0; i < length; i++) { - if (in[i] >= sizeof(BASE58TABLE)) { - return -1; - } - tmp[i] = BASE58TABLE[(int) in[i]]; - if (tmp[i] == 0xff) { - return -1; - } + tmp[i] = BASE58TABLE[(int)in[i]]; + if (tmp[i] == 0xff) { + return -1; } - while ((zeroCount < length) && (tmp[zeroCount] == 0)) { - ++zeroCount; + } + while ((zeroCount < length) && (tmp[zeroCount] == 0)) { + ++zeroCount; + } + j = length; + startAt = zeroCount; + while (startAt < length) { + unsigned short remainder = 0; + unsigned char divLoop; + for (divLoop = startAt; divLoop < length; divLoop++) { + unsigned short digit256 = (unsigned short)(tmp[divLoop] & 0xff); + unsigned short tmpDiv = remainder * 58 + digit256; + tmp[divLoop] = (unsigned char)(tmpDiv / 256); + remainder = (tmpDiv % 256); } - j = length; - startAt = zeroCount; - while (startAt < length) { - unsigned short remainder = 0; - unsigned char divLoop; - for (divLoop = startAt; divLoop < length; divLoop++) { - unsigned short digit256 = (unsigned short) (tmp[divLoop] & 0xff); - unsigned short tmpDiv = remainder * 58 + digit256; - tmp[divLoop] = (unsigned char) (tmpDiv / 256); - remainder = (tmpDiv % 256); - } - if (tmp[startAt] == 0) { - ++startAt; - } - buffer[--j] = (unsigned char) remainder; - } - while ((j < length) && (buffer[j] == 0)) { - ++j; - } - length = length - (j - zeroCount); - if (*outlen < length) { - PRINTF("Decode overflow %d %d\n", length, *outlen); - return -1; + if (tmp[startAt] == 0) { + ++startAt; } + buffer[--j] = (unsigned char)remainder; + } + while ((j < length) && (buffer[j] == 0)) { + ++j; + } + length = length - (j - zeroCount); + if (*outlen < length) { + PRINTF("Decode overflow %d %d\n", length, *outlen); + return -1; + } - os_memmove(out, buffer + j - zeroCount, length); - PRINTF("Decoded\n%.*H\n", length, out); - *outlen = length; - return 0; + memmove(out, buffer + j - zeroCount, length); + PRINTF("Decoded\n%.*H\n",length,out); + *outlen = length; + return 0; } -int btchip_encode_base58(const unsigned char *in, - size_t length, - unsigned char *out, - size_t *outlen) { - unsigned char buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; - size_t i = 0, j; - size_t startAt, stopAt; - size_t zeroCount = 0; - size_t outputSize; +int btchip_encode_base58(const unsigned char *in, size_t length, + unsigned char *out, size_t *outlen) { + unsigned char buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; + size_t i = 0, j; + size_t startAt, stopAt; + size_t zeroCount = 0; + size_t outputSize; - if (length > MAX_ENC_INPUT_SIZE) { - return -1; - } + if (length > MAX_ENC_INPUT_SIZE) { + return -1; + } - PRINTF("Length to encode %d\n", length); - PRINTF("To encode\n%.*H\n", length, in); + PRINTF("Length to encode %d\n", length); + PRINTF("To encode\n%.*H\n",length,in); - while ((zeroCount < length) && (in[zeroCount] == 0)) { - ++zeroCount; - } + while ((zeroCount < length) && (in[zeroCount] == 0)) { + ++zeroCount; + } - outputSize = (length - zeroCount) * 138 / 100 + 1; - stopAt = outputSize - 1; - for (startAt = zeroCount; startAt < length; startAt++) { - int carry = in[startAt]; - for (j = outputSize - 1; (int) j >= 0; j--) { - carry += 256 * buffer[j]; - buffer[j] = carry % 58; - carry /= 58; + outputSize = (length - zeroCount) * 138 / 100 + 1; + stopAt = outputSize - 1; + for (startAt = zeroCount; startAt < length; startAt++) { + int carry = in[startAt]; + for (j = outputSize - 1; (int)j >= 0; j--) { + carry += 256 * buffer[j]; + buffer[j] = carry % 58; + carry /= 58; - if (j <= stopAt - 1 && carry == 0) { - break; - } - } - stopAt = j; + if (j <= stopAt - 1 && carry == 0) { + break; + } } + stopAt = j; + } - j = 0; - while (j < outputSize && buffer[j] == 0) { - j += 1; - } + j = 0; + while (j < outputSize && buffer[j] == 0) { + j += 1; + } - if (*outlen < zeroCount + outputSize - j) { - *outlen = zeroCount + outputSize - j; - return -1; - } + if (*outlen < zeroCount + outputSize - j) { + *outlen = zeroCount + outputSize - j; + return -1; + } - os_memset(out, BASE58ALPHABET[0], zeroCount); + memset(out, BASE58ALPHABET[0], zeroCount); - i = zeroCount; - while (j < outputSize) { - out[i++] = BASE58ALPHABET[buffer[j++]]; - } - *outlen = i; - PRINTF("Length encoded %d\n", i); - PRINTF("Encoded\n%.*H\n", i, out); - return 0; + i = zeroCount; + while (j < outputSize) { + out[i++] = BASE58ALPHABET[buffer[j++]]; + } + *outlen = i; + PRINTF("Length encoded %d\n", i); + PRINTF("Encoded\n%.*H\n",i,out); + return 0; } diff --git a/src/btchip_context.c b/src/btchip_context.c index 687c198..39a9427 100644 --- a/src/btchip_context.c +++ b/src/btchip_context.c @@ -1,36 +1,36 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" -void autosetup(void) { +void autosetup(void){ btchip_config_t config; unsigned char i; unsigned char tmp[32]; - os_memset(&config, 0, sizeof(btchip_config_t)); + explicit_bzero(&config, sizeof(btchip_config_t)); config.options |= BTCHIP_OPTION_DETERMINISTIC_SIGNATURE; - config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when - // supporting multi output + config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when + // supporting multi output - nvm_write((void *) &N_btchip.bkp.config, &config, sizeof(config)); + nvm_write((void *)&N_btchip.bkp.config, &config, sizeof(config)); cx_rng(tmp, sizeof(tmp)); - nvm_write((void *) &N_btchip.bkp.trustedinput_key, tmp, sizeof(tmp)); + nvm_write((void *)&N_btchip.bkp.trustedinput_key, tmp, sizeof(tmp)); i = 1; - nvm_write((void *) &N_btchip.config_valid, &i, 1); + nvm_write((void *)&N_btchip.config_valid, &i, 1); } /** @@ -39,13 +39,15 @@ void autosetup(void) { void btchip_context_init() { PRINTF("Context init\n"); PRINTF(N_btchip.bkp); - os_memset(&btchip_context_D, 0, sizeof(btchip_context_D)); + explicit_bzero(&btchip_context_D, sizeof(btchip_context_D)); SB_SET(btchip_context_D.halted, 0); btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - os_memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); + explicit_bzero(btchip_context_D.totalOutputAmount, + sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; + if (N_btchip.config_valid != 0x01) { autosetup(); } @@ -55,23 +57,24 @@ void btchip_context_init() { PRINTF("No configuration found\n"); defaultMode = BTCHIP_MODE_WALLET; - } else { + } + else { btchip_context_D.payToAddressVersion = G_coin_config->p2pkh_version; btchip_context_D.payToScriptHashVersion = G_coin_config->p2sh_version; btchip_context_D.coinFamily = G_coin_config->family; btchip_context_D.coinIdLength = strlen(PIC(G_coin_config->coinid)); - os_memmove(btchip_context_D.coinId, - PIC(G_coin_config->coinid), + memmove(btchip_context_D.coinId, PIC(G_coin_config->coinid), btchip_context_D.coinIdLength); - btchip_context_D.shortCoinIdLength = strlen(PIC(G_coin_config->name_short)); - os_memmove(btchip_context_D.shortCoinId, - PIC(G_coin_config->name_short), + btchip_context_D.shortCoinIdLength = + strlen(PIC(G_coin_config->name_short)); + memmove(btchip_context_D.shortCoinId, PIC(G_coin_config->name_short), btchip_context_D.shortCoinIdLength); + } if (!N_btchip.storageInitialized) { - unsigned char initialized = 1, denied = 1; + unsigned char initialized = 1, denied=1; - nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &denied, 1); - nvm_write((void *) &N_btchip.storageInitialized, &initialized, 1); + nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &denied, 1); + nvm_write((void *)&N_btchip.storageInitialized, &initialized, 1); } -} \ No newline at end of file +} diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index be25178..d6f4f9b 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -1,44 +1,41 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "blake256.h" const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { - 0x19, - 0x76, - 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = {0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG + 0x19, 0x76, 0xA9, + 0x14}; // script length, OP_DUP, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { + 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x17, - 0xA9, - 0x14}; // script length, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL + 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; unsigned char btchip_output_script_is_regular(unsigned char *buffer) { - if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == - 0) && - (os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, TRANSACTION_OUTPUT_SCRIPT_POST, sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { return 1; @@ -48,10 +45,9 @@ unsigned char btchip_output_script_is_regular(unsigned char *buffer) { } unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { - if ((os_memcmp(buffer, - TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { return 1; @@ -64,13 +60,15 @@ unsigned char btchip_output_script_is_op_return(unsigned char *buffer) { } unsigned char btchip_output_script_is_op_create(unsigned char *buffer) { - return (!btchip_output_script_is_regular(buffer) && !btchip_output_script_is_p2sh(buffer) && + return (!btchip_output_script_is_regular(buffer) && + !btchip_output_script_is_p2sh(buffer) && !btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && (buffer[buffer[0]] == 0xC1)); } unsigned char btchip_output_script_is_op_call(unsigned char *buffer) { - return (!btchip_output_script_is_regular(buffer) && !btchip_output_script_is_p2sh(buffer) && + return (!btchip_output_script_is_regular(buffer) && + !btchip_output_script_is_p2sh(buffer) && !btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && (buffer[buffer[0]] == 0xC2)); } @@ -84,10 +82,12 @@ unsigned char btchip_rng_u8_modulo(unsigned char modulo) { return (candidate % modulo); } -unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, unsigned short length) { +unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, + unsigned short length) { unsigned char error = 0; while (length--) { - error |= ((unsigned char *) buf1)[length] ^ ((unsigned char *) buf2)[length]; + error |= ((unsigned char *)buf1)[length] ^ + ((unsigned char *)buf2)[length]; } if (length != 0xffff) { return 1; @@ -95,16 +95,17 @@ unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, unsigned return error; } -unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, unsigned char skipSign) { +unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, + unsigned char skipSign) { unsigned char i; unsigned long int result = 0; unsigned char shiftValue = (be ? 24 : 0); for (i = 0; i < 4; i++) { - unsigned char x = (unsigned char) buffer[i]; + unsigned char x = (unsigned char)buffer[i]; if ((i == 0) && skipSign) { x &= 0x7f; } - result += ((unsigned long int) x) << shiftValue; + result += ((unsigned long int)x) << shiftValue; if (be) { shiftValue -= 8; } else { @@ -128,15 +129,18 @@ void btchip_write_u32_le(unsigned char *buffer, unsigned long int value) { buffer[3] = ((value >> 24) & 0xff); } -void btchip_retrieve_keypair_discard(unsigned char *privateComponent, unsigned char derivePublic) { +void btchip_retrieve_keypair_discard(unsigned char *privateComponent, + unsigned char derivePublic) { BEGIN_TRY { TRY { - cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, &btchip_private_key_D); + cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, + &btchip_private_key_D); - PRINTF("Using private component\n%.*H\n", 32, privateComponent); + PRINTF("Using private component\n%.*H\n",32,privateComponent); if (derivePublic) { - cx_ecfp_generate_pair(BTCHIP_CURVE, &btchip_public_key_D, &btchip_private_key_D, 1); + cx_ecfp_generate_pair(BTCHIP_CURVE, &btchip_public_key_D, + &btchip_private_key_D, 1); } } FINALLY { @@ -145,7 +149,8 @@ void btchip_retrieve_keypair_discard(unsigned char *privateComponent, unsigned c END_TRY; } -void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out) { +void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, + unsigned char *out) { union { BLAKE256_CTX blake; cx_ripemd160_t riprip; @@ -159,23 +164,21 @@ void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, unsigned cx_hash(&u.riprip.header, CX_LAST, buffer, 32, out, 32); } -unsigned short btchip_public_key_to_encoded_base58(unsigned char *in, - unsigned short inlen, - unsigned char *out, - unsigned short outlen, - unsigned short version, - unsigned char alreadyHashed) { +unsigned short btchip_public_key_to_encoded_base58( + unsigned char *in, unsigned short inlen, unsigned char *out, + unsigned short outlen, unsigned short version, + unsigned char alreadyHashed) { unsigned char tmpBuffer[26]; unsigned char checksumBuffer[32]; - // cx_blake2b_t hash; + //cx_blake2b_t hash; BLAKE256_CTX hash; unsigned char versionSize = (version > 255 ? 2 : 1); size_t outputLen; if (!alreadyHashed) { - PRINTF("To hash\n%.*H\n", inlen, in); + PRINTF("To hash\n%.*H\n",inlen,in); btchip_public_key_hash160(in, inlen, tmpBuffer + versionSize); - PRINTF("Hash160\n%.*H\n", 20, (tmpBuffer + versionSize)); + PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); if (version > 255) { tmpBuffer[0] = (version >> 8); tmpBuffer[1] = version; @@ -183,7 +186,7 @@ unsigned short btchip_public_key_to_encoded_base58(unsigned char *in, tmpBuffer[0] = version; } } else { - os_memmove(tmpBuffer, in, 20 + versionSize); + memmove(tmpBuffer, in, 20 + versionSize); } blake256_Init(&hash); @@ -193,8 +196,8 @@ unsigned short btchip_public_key_to_encoded_base58(unsigned char *in, blake256_Update(&hash, checksumBuffer, 32); blake256_Final(&hash, checksumBuffer); - PRINTF("Checksum\n%.*H\n", 4, checksumBuffer); - os_memmove(tmpBuffer + 20 + versionSize, checksumBuffer, 4); + PRINTF("Checksum\n%.*H\n",4,checksumBuffer); + memmove(tmpBuffer + 20 + versionSize, checksumBuffer, 4); outputLen = outlen; if (btchip_encode_base58(tmpBuffer, 24 + versionSize, out, &outputLen) < 0) { @@ -203,7 +206,8 @@ unsigned short btchip_public_key_to_encoded_base58(unsigned char *in, return outputLen; } -void btchip_swap_bytes(unsigned char *target, unsigned char *source, unsigned char size) { +void btchip_swap_bytes(unsigned char *target, unsigned char *source, + unsigned char size) { unsigned char i; for (i = 0; i < size; i++) { target[i] = source[size - 1 - i]; @@ -217,7 +221,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, unsigned char hashBuffer[32]; cx_sha256_t hash; size_t outputLen = outlen; - if (btchip_decode_base58((char *) in, inlen, out, &outputLen) < 0) { + if (btchip_decode_base58((char *)in, inlen, out, &outputLen) < 0) { THROW(EXCEPTION); } outlen = outputLen; @@ -228,8 +232,8 @@ unsigned short btchip_decode_base58_address(unsigned char *in, cx_sha256_init(&hash); cx_hash(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer, 32); - if (os_memcmp(out + outlen - 4, hashBuffer, 4)) { - PRINTF("Hash checksum mismatch\n%.*H\n", sizeof(hashBuffer), hashBuffer); + if (memcmp(out + outlen - 4, hashBuffer, 4)) { + PRINTF("Hash checksum mismatch\n%.*H\n",sizeof(hashBuffer),hashBuffer); THROW(INVALID_CHECKSUM); } @@ -253,13 +257,10 @@ void btchip_private_derive_keypair(unsigned char *bip32Path, bip32PathInt[i] = btchip_read_u32(bip32Path, 1, 0); bip32Path += 4; } - os_perso_derive_node_bip32(CX_CURVE_256K1, - bip32PathInt, - bip32PathLength, - privateComponent, - out_chainCode); + os_perso_derive_node_bip32(CX_CURVE_256K1, bip32PathInt, bip32PathLength, + privateComponent, out_chainCode); btchip_retrieve_keypair_discard(privateComponent, derivePublic); - os_memset(privateComponent, 0, sizeof(privateComponent)); + explicit_bzero(privateComponent, sizeof(privateComponent)); } /* @@ -267,6 +268,7 @@ Checks if the values of a derivation path are within "normal" (arbitrary) ranges Account < 100, change == 1 or 0, address index < 50000 Returns 1 if the path is unusual, or not compliant with BIP44*/ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path) { + unsigned char i, path_len; unsigned int bip32PathInt[MAX_BIP32_PATH]; @@ -281,19 +283,18 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa bip32Path += 4; } - // If the path length is not compliant with BIP44 or if the purpose/coin type don't match - // regular usage - if (path_len != BIP44_PATH_LEN || ((bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 44 && - (bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 49 && - (bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 84)) { + // If the path length is not compliant with BIP44 or if the purpose/coin type don't match regular usage + if(path_len != BIP44_PATH_LEN || + ((bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && + (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && + (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { return 1; } // If the account or address index is very high or if the change isn't 1, return a warning - if ((bip32PathInt[BIP44_ACCOUNT_OFFSET] ^ 0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path - ? 1 - : 0 || bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + if((bip32PathInt[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || + bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || + bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { return 1; } @@ -301,9 +302,8 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa } // Print a BIP32 path as an ascii string to display on the device screen -// On the Ledger Blue, if the string is longer than 30 char, the string will be split in multiple -// lines -unsigned char bip32_print_path(unsigned char *bip32Path, char *out, unsigned char max_out_len) { +unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len) { + unsigned char bip32PathLength; unsigned char i, offset; unsigned int current_level; @@ -315,79 +315,66 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char *out, unsigned cha } bip32Path++; out[0] = ' '; - offset = 1; + offset=1; for (i = 0; i < bip32PathLength; i++) { current_level = btchip_read_u32(bip32Path, 1, 0); - hardened = (bool) (current_level & 0x80000000); - if (hardened) { - // remove hardening flag + hardened = (bool)(current_level & 0x80000000); + if(hardened) { + //remove hardening flag current_level ^= 0x80000000; } bip32Path += 4; - snprintf(out + offset, max_out_len - offset, "%u", current_level); + snprintf(out+offset, max_out_len-offset, "%u", current_level); offset = strnlen(out, max_out_len); - if (offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); - if (hardened) out[offset++] = '\''; + if(offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); + if(hardened) out[offset++] = '\''; out[offset++] = '/'; out[offset] = '\0'; } // remove last '/' - out[offset - 1] = '\0'; + out[offset-1] = '\0'; - return offset - 1; + return offset -1; } void btchip_transaction_add_output(unsigned char *hash160Address, - unsigned char *amount, - unsigned char p2sh) { - const unsigned char *pre = - (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE : TRANSACTION_OUTPUT_SCRIPT_PRE); - const unsigned char *post = - (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST : TRANSACTION_OUTPUT_SCRIPT_POST); - unsigned char sizePre = - (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); + unsigned char *amount, unsigned char p2sh) { + const unsigned char *pre = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE + : TRANSACTION_OUTPUT_SCRIPT_PRE); + const unsigned char *post = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST + : TRANSACTION_OUTPUT_SCRIPT_POST); + unsigned char sizePre = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); unsigned char sizePost = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST) : sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)); if (amount != NULL) { btchip_swap_bytes(btchip_context_D.tmp, amount, 8); btchip_context_D.tmp += 8; } - os_memmove(btchip_context_D.tmp, (void *) pre, sizePre); + memmove(btchip_context_D.tmp, (void *)pre, sizePre); btchip_context_D.tmp += sizePre; - os_memmove(btchip_context_D.tmp, hash160Address, 20); + memmove(btchip_context_D.tmp, hash160Address, 20); btchip_context_D.tmp += 20; - os_memmove(btchip_context_D.tmp, (void *) post, sizePost); + memmove(btchip_context_D.tmp, (void *)post, sizePost); btchip_context_D.tmp += sizePost; } -void btchip_signverify_finalhash(void *keyContext, - unsigned char sign, - unsigned char *in, - unsigned short inlen, - unsigned char *out, - unsigned short outlen, + +void btchip_signverify_finalhash(void *keyContext, unsigned char sign, + unsigned char *in, unsigned short inlen, + unsigned char *out, unsigned short outlen, unsigned char rfc6979) { if (sign) { unsigned int info = 0; - cx_ecdsa_sign((cx_ecfp_private_key_t *) keyContext, + cx_ecdsa_sign((cx_ecfp_private_key_t *)keyContext, CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), - CX_SHA256, - in, - inlen, - out, - outlen, - &info); + CX_SHA256, in, inlen, out, outlen, &info); if (info & CX_ECCINFO_PARITY_ODD) { out[0] |= 0x01; } } else { - cx_ecdsa_verify((cx_ecfp_public_key_t *) keyContext, - CX_LAST, - CX_SHA256, - in, - inlen, - out, - outlen); + cx_ecdsa_verify((cx_ecfp_public_key_t *)keyContext, CX_LAST, + CX_SHA256, in, inlen, out, outlen); } } diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 84cceee..134d2a4 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -1,19 +1,19 @@ /******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * 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. - ********************************************************************************/ +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* 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. +********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -25,18 +25,18 @@ void check_transaction_available(unsigned char x) { if (btchip_context_D.transactionDataRemaining < x) { - PRINTF("Check transaction available failed %d < %d\n", - btchip_context_D.transactionDataRemaining, - x); + PRINTF("Check transaction available failed %d < %d\n", btchip_context_D.transactionDataRemaining, x); THROW(EXCEPTION); } } -#define OP_HASH160 0xA9 -#define OP_EQUAL 0x87 +#define OP_HASH160 0xA9 +#define OP_EQUAL 0x87 #define OP_CHECKMULTISIG 0xAE -unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, unsigned char *b) { +unsigned char transaction_amount_add_be(unsigned char *target, + unsigned char *a, + unsigned char *b) { unsigned char carry = 0; unsigned char i; for (i = 0; i < 8; i++) { @@ -47,7 +47,9 @@ unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, return carry; } -unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b) { +unsigned char transaction_amount_sub_be(unsigned char *target, + unsigned char *a, + unsigned char *b) { unsigned char borrow = 0; unsigned char i; for (i = 0; i < 8; i++) { @@ -65,7 +67,7 @@ unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, borrow = 1; tmpA += 255 + 1; } - target[8 - 1 - i] = (unsigned char) (tmpA - tmpB); + target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); } return borrow; @@ -73,19 +75,13 @@ unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, void transaction_offset(unsigned char value) { if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { - PRINTF("Add to prefix hash: ", value, btchip_context_D.transactionBufferPointer); - blake256_Update(&btchip_context_D.transactionHashPrefix, - btchip_context_D.transactionBufferPointer, - value); - blake256_Update(&btchip_context_D.transactionHashAuthorization, - btchip_context_D.transactionBufferPointer, - value); + PRINTF("Add to prefix hash: ", value ,btchip_context_D.transactionBufferPointer); + blake256_Update(&btchip_context_D.transactionHashPrefix, btchip_context_D.transactionBufferPointer, value); + blake256_Update(&btchip_context_D.transactionHashAuthorization, btchip_context_D.transactionBufferPointer, value); } if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_WITNESS) != 0) { PRINTF("Add to witness hash: ", value, btchip_context_D.transactionBufferPointer); - blake256_Update(&btchip_context_D.transactionHashWitness, - btchip_context_D.transactionBufferPointer, - value); + blake256_Update(&btchip_context_D.transactionHashWitness, btchip_context_D.transactionBufferPointer, value); } } @@ -106,15 +102,19 @@ unsigned long int transaction_get_varint(void) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(2); - result = (unsigned long int) (*btchip_context_D.transactionBufferPointer) | - ((unsigned long int) (*(btchip_context_D.transactionBufferPointer + 1)) << 8); + result = + (unsigned long int)(*btchip_context_D.transactionBufferPointer) | + ((unsigned long int)(*(btchip_context_D.transactionBufferPointer + + 1)) + << 8); transaction_offset_increase(2); return result; } else if (firstByte == 0xFE) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(4); - result = btchip_read_u32(btchip_context_D.transactionBufferPointer, 0, 0); + result = + btchip_read_u32(btchip_context_D.transactionBufferPointer, 0, 0); transaction_offset_increase(4); return result; } else { @@ -131,461 +131,493 @@ void transaction_parse(unsigned char parseMode) { BEGIN_TRY { TRY { for (;;) { - PRINTF("TX parse, state=%d\n", - btchip_context_D.transactionContext.transactionState); + PRINTF("TX parse, state=%d\n", btchip_context_D.transactionContext.transactionState); switch (btchip_context_D.transactionContext.transactionState) { - case BTCHIP_TRANSACTION_NONE: { - PRINTF("Init transaction parser\n"); - // Reset transaction state - btchip_context_D.transactionContext.transactionRemainingInputsOutputs = 0; - btchip_context_D.transactionContext.transactionCurrentInputOutput = 0; - btchip_context_D.transactionContext.scriptRemaining = 0; - os_memset(btchip_context_D.transactionContext.transactionAmount, - 0, - sizeof(btchip_context_D.transactionContext.transactionAmount)); - // TODO : transactionControlFid - // Reset hashes - blake256_Init(&btchip_context_D.transactionHashPrefix); - blake256_Init(&btchip_context_D.transactionHashWitness); - blake256_Init(&btchip_context_D.transactionHashAuthorization); - // cx_blake2b_init(&btchip_context_D.transactionHashPrefix, 256); - // cx_blake2b_init(&btchip_context_D.transactionHashWitness, 256); - - // Parse the beginning of the transaction - // Version - check_transaction_available(4); - os_memmove(btchip_context_D.transactionVersion, - btchip_context_D.transactionBufferPointer, - 4); - // decred "no witness" serialization type ORing - btchip_context_D.transactionBufferPointer[2] |= 1; - btchip_context_D.transactionHashOption = - TRANSACTION_HASH_FULL; // prefix only - transaction_offset_increase(4); - - btchip_context_D.transactionBufferPointer -= 4; - btchip_context_D.transactionDataRemaining += 4; - btchip_context_D.transactionBufferPointer[2] |= 3; - btchip_context_D.transactionHashOption = - TRANSACTION_HASH_WITNESS; // witness only - transaction_offset_increase(4); - - btchip_context_D.transactionHashOption = - 0x05; // both prefix and witness hash - - // Number of inputs - btchip_context_D.transactionContext.transactionRemainingInputsOutputs = - transaction_get_varint(); - btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; + case BTCHIP_TRANSACTION_NONE: { + PRINTF("Init transaction parser\n"); + // Reset transaction state + btchip_context_D.transactionContext + .transactionRemainingInputsOutputs = 0; + btchip_context_D.transactionContext + .transactionCurrentInputOutput = 0; + btchip_context_D.transactionContext.scriptRemaining = 0; + explicit_bzero( + btchip_context_D.transactionContext.transactionAmount, + sizeof(btchip_context_D.transactionContext + .transactionAmount)); + // TODO : transactionControlFid + // Reset hashes + blake256_Init(&btchip_context_D.transactionHashPrefix); + blake256_Init(&btchip_context_D.transactionHashWitness); + blake256_Init(&btchip_context_D.transactionHashAuthorization); + //cx_blake2b_init(&btchip_context_D.transactionHashPrefix, 256); + //cx_blake2b_init(&btchip_context_D.transactionHashWitness, 256); + + + // Parse the beginning of the transaction + // Version + check_transaction_available(4); + memmove(btchip_context_D.transactionVersion, + btchip_context_D.transactionBufferPointer, 4); + // decred "no witness" serialization type ORing + btchip_context_D.transactionBufferPointer[2] |= 1; + btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; // prefix only + transaction_offset_increase(4); + + btchip_context_D.transactionBufferPointer -= 4; + btchip_context_D.transactionDataRemaining += 4; + btchip_context_D.transactionBufferPointer[2] |= 3; + btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; // witness only + transaction_offset_increase(4); + + btchip_context_D.transactionHashOption = 0x05; // both prefix and witness hash + + + // Number of inputs + btchip_context_D.transactionContext + .transactionRemainingInputsOutputs = + transaction_get_varint(); + btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; + + // Ready to proceed + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + + // no break is intentional + } - // Ready to proceed + case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { + unsigned char trustedInputFlag = 1; + PRINTF("Process input\n"); + if (btchip_context_D.transactionContext + .transactionRemainingInputsOutputs == 0) { + // No more inputs to hash, move forward btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - - // no break is intentional + BTCHIP_TRANSACTION_INPUT_HASHING_DONE; + continue; } - - case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { - unsigned char trustedInputFlag = 1; - PRINTF("Process input\n"); - if (btchip_context_D.transactionContext.transactionRemainingInputsOutputs == - 0) { - // No more inputs to hash, move forward - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_DONE; - continue; + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + PRINTF("Waiting for more data...\n"); + goto ok; + } + // Proceed with the next input + if (parseMode == PARSE_MODE_TRUSTED_INPUT) { + PRINTF("PARSE_MODE_TRUSTED_INPUT\n"); + check_transaction_available( + 37); // prevout : 32 hash + 4 index + 1 tree + transaction_offset_increase(37); + } + if (parseMode == PARSE_MODE_SIGNATURE) { + PRINTF("PARSE_MODE_SIGNATURE\n"); + unsigned char trustedInputLength; + unsigned char trustedInput[0x38]; + unsigned char amount[8]; + unsigned char *savePointer; + + // Expect the trusted input flag and trusted input + // length + check_transaction_available(2); + switch (*btchip_context_D.transactionBufferPointer) { + case 0: + trustedInputFlag = 0; + break; + case 1: + trustedInputFlag = 1; + break; + + default: + PRINTF("Invalid trusted input flag\n"); + goto fail; } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - PRINTF("Waiting for more data...\n"); - goto ok; + /* + trustedInputLength = + *(btchip_context_D.transactionBufferPointer + 1); + if (trustedInputLength > sizeof(trustedInput)) { + PRINTF("Trusted input too long\n"); + goto fail; } - // Proceed with the next input - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - PRINTF("PARSE_MODE_TRUSTED_INPUT\n"); + */ + + if (!trustedInputFlag) { + + if (!optionP2SHSkip2FA) { + PRINTF("Untrusted input not authorized\n"); + goto fail; + } + + btchip_context_D.transactionBufferPointer++; + btchip_context_D.transactionDataRemaining--; check_transaction_available( - 37); // prevout : 32 hash + 4 index + 1 tree - transaction_offset_increase(37); - } - if (parseMode == PARSE_MODE_SIGNATURE) { - PRINTF("PARSE_MODE_SIGNATURE\n"); - unsigned char trustedInputLength; - unsigned char trustedInput[0x38]; - unsigned char amount[8]; - unsigned char *savePointer; - - // Expect the trusted input flag and trusted input - // length - check_transaction_available(2); - switch (*btchip_context_D.transactionBufferPointer) { - case 0: - trustedInputFlag = 0; - break; - case 1: - trustedInputFlag = 1; - break; - - default: - PRINTF("Invalid trusted input flag\n"); - goto fail; + 36); // prevout : 32 hash + 4 index + transaction_offset_increase(36); + PRINTF("Marking relaxed input\n"); + btchip_context_D.transactionContext.relaxed = 1; + /* + PRINTF("Clearing P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 0; + */ + } else { + trustedInputLength = *( + btchip_context_D.transactionBufferPointer + 1); + if ((trustedInputLength > sizeof(trustedInput)) || + (trustedInputLength < 8)) { + PRINTF("Invalid trusted input size\n"); + goto fail; } + + check_transaction_available(2 + trustedInputLength); + cx_hmac_sha256( + (const uint8_t *) N_btchip.bkp.trustedinput_key, + sizeof(N_btchip.bkp.trustedinput_key), + btchip_context_D.transactionBufferPointer + 2, + trustedInputLength - 8, trustedInput, trustedInputLength); + if (btchip_secure_memcmp( + trustedInput, + btchip_context_D.transactionBufferPointer + + 2 + trustedInputLength - 8, + 8) != 0) { + PRINTF("Invalid signature\n"); + goto fail; + } + memmove( + trustedInput, + btchip_context_D.transactionBufferPointer + 2, + trustedInputLength - 8); + if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { + PRINTF("Failed to verify trusted input signature\n"); + goto fail; + } + else { + PRINTF("Good Signature\n"); + } + + // Update the hash with prevout data + savePointer = + btchip_context_D.transactionBufferPointer; //trusted input 01 /* - trustedInputLength = - *(btchip_context_D.transactionBufferPointer + 1); - if (trustedInputLength > sizeof(trustedInput)) { - PRINTF("Trusted input too long\n"); - goto fail; + // Check if a P2SH script is used + if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == + 0) { + PRINTF("Clearing P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = + 0; } */ + btchip_context_D.transactionBufferPointer = + trustedInput + 4; + PRINTF("Trusted input hash\n%.*H\n",36,btchip_context_D.transactionBufferPointer); + transaction_offset(36); + + btchip_context_D.transactionBufferPointer = + savePointer + (2 + trustedInputLength); + btchip_context_D.transactionDataRemaining -= + (2 + trustedInputLength); + + // add Decred tree + check_transaction_available(1); + transaction_offset_increase(1); - if (!trustedInputFlag) { - if (!optionP2SHSkip2FA) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - - btchip_context_D.transactionBufferPointer++; - btchip_context_D.transactionDataRemaining--; - check_transaction_available(36); // prevout : 32 hash + 4 index - transaction_offset_increase(36); - PRINTF("Marking relaxed input\n"); - btchip_context_D.transactionContext.relaxed = 1; - /* - PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; - */ - } else { - trustedInputLength = - *(btchip_context_D.transactionBufferPointer + 1); - if ((trustedInputLength > sizeof(trustedInput)) || - (trustedInputLength < 8)) { - PRINTF("Invalid trusted input size\n"); - goto fail; - } - - check_transaction_available(2 + trustedInputLength); - cx_hmac_sha256(N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), - btchip_context_D.transactionBufferPointer + 2, - trustedInputLength - 8, - trustedInput, - trustedInputLength); - if (btchip_secure_memcmp(trustedInput, - btchip_context_D.transactionBufferPointer + - 2 + trustedInputLength - 8, - 8) != 0) { - PRINTF("Invalid signature\n"); - goto fail; - } - os_memmove(trustedInput, - btchip_context_D.transactionBufferPointer + 2, - trustedInputLength - 8); - if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { - PRINTF("Failed to verify trusted input signature\n"); - goto fail; - } else { - PRINTF("Good Signature\n"); - } - - // Update the hash with prevout data - savePointer = - btchip_context_D.transactionBufferPointer; // trusted input 01 - /* - // Check if a P2SH script is used - if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == - 0) { - PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = - 0; - } - */ - btchip_context_D.transactionBufferPointer = trustedInput + 4; - PRINTF("Trusted input hash\n%.*H\n", - 36, - btchip_context_D.transactionBufferPointer); - transaction_offset(36); - - btchip_context_D.transactionBufferPointer = - savePointer + (2 + trustedInputLength); - btchip_context_D.transactionDataRemaining -= - (2 + trustedInputLength); - - // add Decred tree - check_transaction_available(1); - transaction_offset_increase(1); - - // Update the amount - - btchip_swap_bytes(amount, trustedInput + 40, 8); - if (transaction_amount_add_be( - btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.transactionContext.transactionAmount, - amount)) { - PRINTF("Overflow\n"); - goto fail; - } - - PRINTF("Adding amount\n%.*H\n", 8, (trustedInput + 40)); - PRINTF("New amount\n%.*H\n", - 8, - btchip_context_D.transactionContext.transactionAmount); + // Update the amount + + btchip_swap_bytes(amount, trustedInput + 40, 8); + if (transaction_amount_add_be( + btchip_context_D.transactionContext + .transactionAmount, + btchip_context_D.transactionContext + .transactionAmount, + amount)) { + PRINTF("Overflow\n"); + goto fail; } - } - // DIRTY: include utxo script len and script in witness hash - btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; - // Read the script length - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n", - btchip_context_D.transactionContext.scriptRemaining); - - if ((parseMode == PARSE_MODE_SIGNATURE) && !trustedInputFlag) { - // Only proceeds if this is not to be signed - so length - // should be null - if (btchip_context_D.transactionContext.scriptRemaining != 0) { - PRINTF("Request to sign relaxed input\n"); - if (!optionP2SHSkip2FA) { - goto fail; - } - } + PRINTF("Adding amount\n%.*H\n",8,(trustedInput + 40)); + PRINTF("New amount\n%.*H\n",8,btchip_context_D.transactionContext.transactionAmount); } - PRINTF("NEXT_STATE\n"); - // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - // no break is intentional + } - case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process input script, remaining " DEBUG_LONG "\n", - btchip_context_D.transactionContext.scriptRemaining); - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Scan for P2SH consumption - huge shortcut, but fine - // enough - // Also usable in SegWit mode - if (btchip_context_D.transactionContext.scriptRemaining == 1) { - if (*btchip_context_D.transactionBufferPointer == OP_CHECKMULTISIG) { - if (optionP2SHSkip2FA) { - PRINTF("Marking P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 1; - } - } else { - // When using the P2SH shortcut, all inputs must use - // P2SH - PRINTF("Disabling P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; + // DIRTY: include utxo script len and script in witness hash + btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; + + // Read the script length + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); + PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); + + if ((parseMode == PARSE_MODE_SIGNATURE) && + !trustedInputFlag) { + // Only proceeds if this is not to be signed - so length + // should be null + if (btchip_context_D.transactionContext + .scriptRemaining != 0) { + PRINTF("Request to sign relaxed input\n"); + if (!optionP2SHSkip2FA) { + goto fail; } - transaction_offset_increase(1); - btchip_context_D.transactionContext.scriptRemaining--; } + } + PRINTF("NEXT_STATE\n"); + // Move on + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - if (btchip_context_D.transactionContext.scriptRemaining == 0) { - // restore full hash - btchip_context_D.transactionHashOption = 0x01; - - if (parseMode == PARSE_MODE_SIGNATURE) { - btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; + // no break is intentional + } + case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process input script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Scan for P2SH consumption - huge shortcut, but fine + // enough + // Also usable in SegWit mode + if (btchip_context_D.transactionContext.scriptRemaining == + 1) { + if (*btchip_context_D.transactionBufferPointer == + OP_CHECKMULTISIG) { + if (optionP2SHSkip2FA) { + PRINTF("Marking P2SH consumption\n"); + btchip_context_D.transactionContext + .consumeP2SH = 1; } - // Sequence - check_transaction_available(4); - transaction_offset_increase(4); - // Move to next input - btchip_context_D.transactionContext.transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext.transactionCurrentInputOutput++; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - continue; - } - // Save the last script byte for the P2SH check - dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext.scriptRemaining - 1 - ? btchip_context_D.transactionContext.scriptRemaining - 1 - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; + } else { + // When using the P2SH shortcut, all inputs must use + // P2SH + PRINTF("Disabling P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 0; } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; - break; + transaction_offset_increase(1); + btchip_context_D.transactionContext.scriptRemaining--; } - case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { - PRINTF("Input hashing done\n"); + + if (btchip_context_D.transactionContext.scriptRemaining == + 0) { + // restore full hash + btchip_context_D.transactionHashOption = 0x01; + if (parseMode == PARSE_MODE_SIGNATURE) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PRESIGN_READY; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; + btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; } - // Number of outputs - btchip_context_D.transactionContext.transactionRemainingInputsOutputs = - transaction_get_varint(); - btchip_context_D.transactionContext.transactionCurrentInputOutput = 0; - PRINTF( - "Number of outputs : " DEBUG_LONG "\n", - btchip_context_D.transactionContext.transactionRemainingInputsOutputs); - // Ready to proceed + // Sequence + check_transaction_available(4); + transaction_offset_increase(4); + // Move to next input + btchip_context_D.transactionContext + .transactionRemainingInputsOutputs--; + btchip_context_D.transactionContext + .transactionCurrentInputOutput++; btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - - // no break is intentional + BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + continue; } - case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { - if (btchip_context_D.transactionContext.transactionRemainingInputsOutputs == - 0) { - // No more outputs to hash, move forward - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Amount - check_transaction_available(8); - if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && - (btchip_context_D.transactionContext.transactionCurrentInputOutput == - btchip_context_D.transactionTargetInput)) { - // Save the amount - os_memmove(btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.transactionBufferPointer, - 8); - btchip_context_D.trustedInputProcessed = 1; - PRINTF("Input processed\n"); - } - transaction_offset_increase(8); + // Save the last script byte for the P2SH check + dataAvailable = + (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext + .scriptRemaining - + 1 + ? btchip_context_D.transactionContext + .scriptRemaining - + 1 + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= + dataAvailable; + break; + } + case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { + PRINTF("Input hashing done\n"); + if (parseMode == PARSE_MODE_SIGNATURE) { + + btchip_context_D.transactionContext + .transactionState = + BTCHIP_TRANSACTION_PRESIGN_READY; + continue; + } + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Number of outputs + btchip_context_D.transactionContext + .transactionRemainingInputsOutputs = + transaction_get_varint(); + btchip_context_D.transactionContext + .transactionCurrentInputOutput = 0; + PRINTF("Number of outputs : " DEBUG_LONG "\n", btchip_context_D.transactionContext .transactionRemainingInputsOutputs); + // Ready to proceed + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; + + // no break is intentional + } + case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { + if (btchip_context_D.transactionContext + .transactionRemainingInputsOutputs == 0) { + // No more outputs to hash, move forward + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; + continue; + } + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Amount + check_transaction_available(8); + if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && + (btchip_context_D.transactionContext + .transactionCurrentInputOutput == + btchip_context_D.transactionTargetInput)) { + // Save the amount + memmove(btchip_context_D.transactionContext + .transactionAmount, + btchip_context_D.transactionBufferPointer, + 8); + btchip_context_D.trustedInputProcessed = 1; + PRINTF("Input processed\n"); + } + transaction_offset_increase(8); - // script version - check_transaction_available(2); - transaction_offset_increase(2); + // script version + check_transaction_available(2); + transaction_offset_increase(2); - // Read the script length - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); + // Read the script length + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n", - btchip_context_D.transactionContext.scriptRemaining); - // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; + PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); + // Move on + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; - // no break is intentional + // no break is intentional + } + case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process output script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); + /* + // Special check if consuming a P2SH script + if (parseMode == PARSE_MODE_TRUSTED_INPUT) { + // Assume the full input script is sent in a single APDU, + then do the ghetto validation + if ((btchip_context_D.transactionBufferPointer[0] == + OP_HASH160) && + (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining + - 1] == OP_EQUAL)) { + PRINTF("Marking P2SH output\n"); + btchip_context_D.transactionContext.consumeP2SH = 1; + } } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process output script, remaining " DEBUG_LONG "\n", - btchip_context_D.transactionContext.scriptRemaining); - /* - // Special check if consuming a P2SH script - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - // Assume the full input script is sent in a single APDU, - then do the ghetto validation - if ((btchip_context_D.transactionBufferPointer[0] == - OP_HASH160) && - (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining - - 1] == OP_EQUAL)) { - PRINTF("Marking P2SH output\n"); - btchip_context_D.transactionContext.consumeP2SH = 1; - } - } - */ - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - if (btchip_context_D.transactionContext.scriptRemaining == 0) { - // Move to next output - btchip_context_D.transactionContext.transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext.transactionCurrentInputOutput++; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - continue; - } - dataAvailable = (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext.scriptRemaining - ? btchip_context_D.transactionContext.scriptRemaining - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; - break; + */ + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { - PRINTF("Output hashing done\n"); - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Locktime + Expiration - check_transaction_available(4 + 4); - transaction_offset_increase(4 + 4); - - if (btchip_context_D.transactionDataRemaining == 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; - continue; - } else { - btchip_context_D.transactionHashOption = 0; - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); - btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PROCESS_EXTRA; - continue; - } + if (btchip_context_D.transactionContext.scriptRemaining == + 0) { + // Move to next output + btchip_context_D.transactionContext + .transactionRemainingInputsOutputs--; + btchip_context_D.transactionContext + .transactionCurrentInputOutput++; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; + continue; } + dataAvailable = + (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext + .scriptRemaining + ? btchip_context_D.transactionContext + .scriptRemaining + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= + dataAvailable; + break; + } + case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { + PRINTF("Output hashing done\n"); + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Locktime + Expiration + check_transaction_available(4+4); + transaction_offset_increase(4+4); - case BTCHIP_TRANSACTION_PROCESS_EXTRA: { - unsigned char dataAvailable; - - if (btchip_context_D.transactionContext.scriptRemaining == 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; - continue; - } + if (btchip_context_D.transactionDataRemaining == 0) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PARSED; + continue; + } else { + btchip_context_D.transactionHashOption = 0; + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); + btchip_context_D.transactionHashOption = + TRANSACTION_HASH_FULL; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PROCESS_EXTRA; + continue; + } + } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } + case BTCHIP_TRANSACTION_PROCESS_EXTRA: { + unsigned char dataAvailable; - dataAvailable = (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext.scriptRemaining - ? btchip_context_D.transactionContext.scriptRemaining - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; - break; + if (btchip_context_D.transactionContext.scriptRemaining == + 0) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PARSED; + continue; } - case BTCHIP_TRANSACTION_PARSED: { - PRINTF("Transaction parsed\n"); + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok goto ok; } - case BTCHIP_TRANSACTION_PRESIGN_READY: { - PRINTF("Presign ready\n"); + dataAvailable = + (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext + .scriptRemaining + ? btchip_context_D.transactionContext + .scriptRemaining + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { goto ok; } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= + dataAvailable; + break; + } - case BTCHIP_TRANSACTION_SIGN_READY: { - PRINTF("Sign ready\n"); - goto ok; - } + case BTCHIP_TRANSACTION_PARSED: { + PRINTF("Transaction parsed\n"); + goto ok; + } + + case BTCHIP_TRANSACTION_PRESIGN_READY: { + PRINTF("Presign ready\n"); + goto ok; + } + + case BTCHIP_TRANSACTION_SIGN_READY: { + PRINTF("Sign ready\n"); + goto ok; + } } } @@ -596,7 +628,8 @@ void transaction_parse(unsigned char parseMode) { } CATCH_OTHER(e) { PRINTF("Transaction parse - surprise fail\n"); - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); THROW(e); } diff --git a/src/main.c b/src/main.c index 3300855..6d8c757 100644 --- a/src/main.c +++ b/src/main.c @@ -707,6 +707,7 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { } unsigned char io_event(unsigned char channel) { + UNUSED(channel); // nothing done with the event, throw an error on the transport layer if // needed @@ -1223,7 +1224,7 @@ __attribute__((section(".boot"))) int main(int arg0) { strcpy(name_short, COIN_COINID_SHORT); btchip_altcoin_config_t coin_config; - os_memmove(&coin_config, &C_coin_config, sizeof(coin_config)); + memmove(&coin_config, &C_coin_config, sizeof(coin_config)); coin_config.coinid = coinid; coin_config.name = name; coin_config.name_short = name_short; diff --git a/src/ui/pubkey/ui_pubkey_bagl.c b/src/ui/pubkey/ui_pubkey_bagl.c index 4b4dc91..ef00c24 100644 --- a/src/ui/pubkey/ui_pubkey_bagl.c +++ b/src/ui/pubkey/ui_pubkey_bagl.c @@ -115,6 +115,7 @@ unsigned int ui_display_address_nanos_prepro(const bagl_element_t *element) { unsigned int ui_display_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { + UNUSED(button_mask_counter); if (ux_step == 3) { switch (button_mask) @@ -163,6 +164,7 @@ unsigned int ui_display_address_nanos_button(unsigned int button_mask, unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { + UNUSED(button_mask_counter); switch (button_mask) { case BUTTON_EVT_RELEASED | BUTTON_LEFT: @@ -178,6 +180,7 @@ unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, unsigned int ui_display_token_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { + UNUSED(button_mask_counter); switch (button_mask) { case BUTTON_EVT_RELEASED | BUTTON_LEFT: @@ -321,7 +324,7 @@ UX_FLOW(ux_display_token_flow, void ui_display_public_key(unsigned char* derivation_path) { // append a white space at the end of the address to avoid glitch on nano S - strcat(G_io_apdu_buffer + 200, " "); + strcat((char*)G_io_apdu_buffer + 200, " "); bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 3882a83..e22be98 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -22,12 +22,12 @@ #include "ux.h" #define COLOR_WHITE 0xFFFFFF -#define UI_NANOS_BACKGROUND() {{BAGL_RECTANGLE,0,0,0,128,32,0,0,BAGL_FILL,0,COLOR_WHITE,0,0},NULL,0,0,0,NULL,NULL,NULL} -#define UI_NANOS_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,0},(char *)text,0,0,0,NULL,NULL,NULL} -#define UI_NANOS_ICON_LEFT(userid, glyph) {{BAGL_ICON,userid,3,12,7,7,0,0,0,COLOR_WHITE,0,0,glyph},NULL,0,0,0,NULL,NULL,NULL} -#define UI_NANOS_ICON_RIGHT(userid, glyph) {{BAGL_ICON,userid,117,13,8,6,0,0,0,COLOR_WHITE,0,0,glyph},NULL,0,0,0,NULL,NULL,NULL} +#define UI_NANOS_BACKGROUND() {{BAGL_RECTANGLE,0,0,0,128,32,0,0,BAGL_FILL,0,COLOR_WHITE,0,0},NULL} +#define UI_NANOS_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,0},(char *)text} +#define UI_NANOS_ICON_LEFT(userid, glyph) {{BAGL_ICON,userid,3,12,7,7,0,0,0,COLOR_WHITE,0,0,glyph},NULL} +#define UI_NANOS_ICON_RIGHT(userid, glyph) {{BAGL_ICON,userid,117,13,8,6,0,0,0,COLOR_WHITE,0,0,glyph},NULL} // Only one scrolling text per screen can be displayed -#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0x80|10,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,26},(char *)text,0,0,0,NULL,NULL,NULL} +#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0x80|10,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,26},(char *)text} typedef union { struct { From dfa9086139338d0221d1cd678de2383d62439c54 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 28 Nov 2022 18:10:04 +0100 Subject: [PATCH 12/41] Move BAGL transaction UX code to separate file. --- src/btchip_apdu_hash_input_finalize_full.c | 1 + src/btchip_apdu_sign_message.c | 1 + src/btchip_bagl_extensions.h | 16 - src/main.c | 1017 -------------------- src/ui/transaction/ui_transaction.h | 23 + src/ui/transaction/ui_transaction_bagl.c | 637 ++++++++++++ src/ui/ui_shared.c | 408 ++++++++ src/ui/ui_shared.h | 12 + 8 files changed, 1082 insertions(+), 1033 deletions(-) create mode 100644 src/ui/transaction/ui_transaction.h create mode 100644 src/ui/transaction/ui_transaction_bagl.c diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index e4c7187..d126374 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -21,6 +21,7 @@ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" +#include "ui_transaction.h" #define FINALIZE_P1_MORE 0x00 #define FINALIZE_P1_LAST 0x80 diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index b74f2a8..035b5ae 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -18,6 +18,7 @@ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" +#include "ui_transaction.h" #define P1_PREPARE 0x00 #define P1_SIGN 0x80 diff --git a/src/btchip_bagl_extensions.h b/src/btchip_bagl_extensions.h index 11029b4..1bdb83b 100644 --- a/src/btchip_bagl_extensions.h +++ b/src/btchip_bagl_extensions.h @@ -18,28 +18,12 @@ #ifndef _BTCHIP_BAGL_H_ #define _BTCHIP_BAGL_H_ -// btchip asking the legacy grouped UI -unsigned int btchip_bagl_confirm_full_output(void); - -// btchip asking the per-output UI -unsigned int btchip_bagl_confirm_single_output(void); - -// btchip display token -void btchip_bagl_display_token(void); - -// btchip finalizing the transaction -unsigned int btchip_bagl_finalize_tx(void); - // UI response to btchip to finish the exchange unsigned char btchip_bagl_user_action(unsigned char confirming); -// btchip asking message signing confirmation -void btchip_bagl_confirm_message_signature(void); - // UI response to message signature void btchip_bagl_user_action_message_signing(unsigned char confirming); void btchip_bagl_user_action_display(unsigned char confirming); -void btchip_bagl_request_change_path_approval(unsigned char* change_path); #endif /* _BTCHIP_BAGL_H_ */ diff --git a/src/main.c b/src/main.c index 6d8c757..dc874cd 100644 --- a/src/main.c +++ b/src/main.c @@ -53,14 +53,6 @@ unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; #define COLOR_LIGHT_GRAY 0xEEEEEE #ifndef TARGET_FATSTACKS -unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e); -unsigned int -io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e); -unsigned int -io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e); -unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e); unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e); #endif @@ -80,598 +72,7 @@ const bagl_element_t *ui_menu_item_out_over(const bagl_element_t *e) { e = (const bagl_element_t *)(((unsigned int)e) + sizeof(bagl_element_t)); return e; } -#endif - -#if defined(TARGET_NANOS) - -const bagl_element_t ui_request_change_path_approval_nanos[] = { - UI_NANOS_BACKGROUND(), - - UI_NANOS_TEXT(1, 0, 22, 128, "Warning !", BAGL_FONT_OPEN_SANS_LIGHT_16px), - - UI_NANOS_TEXT(2, 0, 12, 128, "The change path", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(2, 0, 26, 128, "is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Change path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; - -unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); - if (display) { - if (element->component.userid & 0x80) { - ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - } - } - return display; - } - return 1; -} - -unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -const bagl_element_t ui_verify_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, "transaction", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Amount", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(4, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(4, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) - -}; -unsigned int ui_verify_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -const bagl_element_t ui_verify_output_nanos[] = { - - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Amount", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; - -unsigned int ui_verify_output_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -const bagl_element_t ui_finalize_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, "transaction", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) - - - /* TODO - {{BAGL_LABELINE , 0x02, 0, 12, 128, 12, 0, 0, 0 , - COLOR_WHITE, COLOR_BLACK, - BAGL_FONT_OPEN_SANS_REGULAR_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Amount", - 0, 0, 0, NULL, NULL, NULL }, - {{BAGL_LABELINE , 0x02, 23, 26, 82, 12, 0x80|10, - 0, 0 , COLOR_WHITE, COLOR_BLACK, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 26 }, - vars.tmp.fullAmount, 0, 0, 0, NULL, NULL, NULL }, - */ -}; -unsigned int ui_finalize_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -// display or not according to step, and adjust delay -unsigned int ui_verify_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - case 4: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -unsigned int ui_verify_output_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -unsigned int ui_finalize_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -const bagl_element_t ui_verify_message_signature_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Sign the", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, "message", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Message hash", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; -unsigned int -ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -unsigned int ui_verify_message_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -#endif // #if defined(TARGET_NANOS) -#ifndef TARGET_FATSTACKS -unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { - // user denied the transaction, tell the USB side - if (!btchip_bagl_user_action(0)) { - // redraw ui - ui_idle(); - } - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { - // user accepted the transaction, tell the USB side - if (!btchip_bagl_user_action(1)) { - // redraw ui - ui_idle(); - } - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int -io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { - // user denied the transaction, tell the USB side - btchip_bagl_user_action_message_signing(0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int -io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { - // user accepted the transaction, tell the USB side - btchip_bagl_user_action_message_signing(1); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e) { - // revoke previous valid token if there was one - btchip_context_D.has_valid_token = false; - // user denied the token, tell the USB side - btchip_bagl_user_action_display(0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - - unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e) { - // Set the valid token flag - btchip_context_D.has_valid_token = true; - // user approved the token, tell the USB side - btchip_bagl_user_action_display(1); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} -#endif - -#if defined(TARGET_NANOS) -unsigned int ui_verify_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; - } - return 0; -} - -unsigned int ui_verify_output_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; - } - return 0; -} - -unsigned int ui_finalize_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; - } - return 0; -} - -unsigned int -ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_message_signature_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_message_signature_verify_ok(NULL); - break; - } - return 0; -} - - unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ - if (ux_step == 3) - { - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } - else - { - if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) - { - // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) - if(ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - } - } - return 0; -} - -#endif // #if defined(TARGET_NANOS) - -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_sign_flow_1_step, - pnn, - { - &C_icon_certificate, - "Sign", - "message", - }); -UX_STEP_NOCB( - ux_sign_flow_2_step, - bnnn_paging, - { - .title = "Message hash", - .text = vars.tmp.fullAddress, - }); -UX_STEP_VALID( - ux_sign_flow_3_step, - pbb, - io_seproxyhal_touch_message_signature_verify_ok(NULL), - { - &C_icon_validate_14, - "Sign", - "message", - }); -UX_STEP_VALID( - ux_sign_flow_4_step, - pbb, - io_seproxyhal_touch_message_signature_verify_cancel(NULL), - { - &C_icon_crossmark, - "Cancel", - "signature", - }); - -UX_FLOW(ux_sign_flow, - &ux_sign_flow_1_step, - &ux_sign_flow_2_step, - &ux_sign_flow_3_step, - &ux_sign_flow_4_step -); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_confirm_full_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction", - }); -UX_STEP_NOCB( - ux_confirm_full_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount - }); -UX_STEP_NOCB( - ux_confirm_full_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB( - ux_confirm_full_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_confirm_full_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send", - }); -UX_STEP_VALID( - ux_confirm_full_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress / Fees: feesAmount -UX_FLOW(ux_confirm_full_flow, - &ux_confirm_full_flow_1_step, - &ux_confirm_full_flow_2_step, - &ux_confirm_full_flow_3_step, - &ux_confirm_full_flow_4_step, - &ux_confirm_full_flow_5_step, - &ux_confirm_full_flow_6_step -); - -////////////////////////////////////////////////////////////////////// - -UX_STEP_NOCB( - ux_confirm_single_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction" - }); -UX_STEP_NOCB( - ux_confirm_single_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount, - }); -UX_STEP_NOCB( - ux_confirm_single_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB( - ux_confirm_single_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_confirm_single_flow_5_step, - pb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - }); -UX_STEP_VALID( - ux_confirm_single_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: fullAddress -UX_FLOW(ux_confirm_single_flow, - &ux_confirm_single_flow_1_step, - &ux_confirm_single_flow_2_step, - &ux_confirm_single_flow_3_step, - &ux_confirm_single_flow_4_step, - &ux_confirm_single_flow_5_step, - &ux_confirm_single_flow_6_step -); - -////////////////////////////////////////////////////////////////////// - -UX_STEP_NOCB( - ux_finalize_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction" - }); -UX_STEP_NOCB( - ux_finalize_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_finalize_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send" - }); -UX_STEP_VALID( - ux_finalize_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// finalize: confirm transaction / Fees: feesAmount -UX_FLOW(ux_finalize_flow, - &ux_finalize_flow_1_step, - &ux_finalize_flow_4_step, - &ux_finalize_flow_5_step, - &ux_finalize_flow_6_step -); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_request_change_path_approval_flow_1_step, - pbb, - { - &C_icon_eye, - "The change path", - "is unusual", - }); -UX_STEP_NOCB( - ux_request_change_path_approval_flow_2_step, - bnnn_paging, - { - .title = "Change path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_VALID( - ux_request_change_path_approval_flow_3_step, - pbb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_VALID( - ux_request_change_path_approval_flow_4_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); - -UX_FLOW(ux_request_change_path_approval_flow, - &ux_request_change_path_approval_flow_1_step, - &ux_request_change_path_approval_flow_2_step, - &ux_request_change_path_approval_flow_3_step, - &ux_request_change_path_approval_flow_4_step -); - -#endif // TARGET_NANOX || TARGET_NANOS2 - -#ifndef TARGET_FATSTACKS // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { @@ -710,7 +111,6 @@ unsigned char io_event(unsigned char channel) { UNUSED(channel); // nothing done with the event, throw an error on the transport layer if // needed - // can't have more than one tag in the reply, not supported yet. switch (G_io_seproxyhal_spi_buffer[0]) { case SEPROXYHAL_TAG_FINGER_EVENT: @@ -764,423 +164,6 @@ unsigned char io_event(unsigned char channel) { return 1; } -uint8_t prepare_fees() { - if (btchip_context_D.transactionContext.relaxed) { - os_memmove(vars.tmp.feesAmount, "UNKNOWN", 7); - vars.tmp.feesAmount[7] = '\0'; - } else { - unsigned char fees[8]; - unsigned short textSize; - if (transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.totalOutputAmount)) { - PRINTF("Fees: %.*H\n", 8, fees); - PRINTF("transactionAmount:: %.*H\n", 8, btchip_context_D.transactionContext.transactionAmount); - PRINTF("totalOutputAmount: %.*H\n", 8, btchip_context_D.totalOutputAmount); - PRINTF("Error : Fees not consistent"); - goto error; - } - os_memmove(vars.tmp.feesAmount, btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); - vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; - btchip_context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - btchip_context_D.shortCoinIdLength + 1); - textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = - '\0'; - } - return 1; -error: - return 0; -} - -uint8_t prepare_single_output() { - // TODO : special display for OP_RETURN - unsigned char amount[8]; - char tmp[80]; - unsigned int offset = 0; - unsigned char versionSize; - int addressOffset; - unsigned char address[22]; - unsigned short version; // addr prefix, or net id - unsigned short textSize; - unsigned char script_version[2]; // Decred thing - - vars.tmp.fullAddress[0] = '\0'; - btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); - offset += 8; - - btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; - - PRINTF("amount: %.*H\n", 8, amount); - - if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + - offset)) { - strcpy(vars.tmp.fullAddress, "OP_RETURN"); - } - else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + - offset)) { - addressOffset = offset + 4; - version = btchip_context_D.payToAddressVersion; - } - else { - addressOffset = offset + 3; - version = btchip_context_D.payToScriptHashVersion; - } - if (vars.tmp.fullAddress[0] == 0) { - - if (version > 255) { - versionSize = 2; - address[0] = (version >> 8); - address[1] = version; - } else { - versionSize = 1; - address[0] = version; - } - os_memmove(address + versionSize, - btchip_context_D.currentOutput + addressOffset, 20); - - // Prepare address - textSize = btchip_public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)tmp, - sizeof(tmp), version, 1); - tmp[textSize] = '\0'; - - strcpy(vars.tmp.fullAddress, tmp); - } - - // Prepare amount - - os_memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); - vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; - btchip_context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - btchip_context_D.shortCoinIdLength + 1); - textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = - '\0'; - - return 1; -} - -uint8_t prepare_full_output(uint8_t checkOnly) { - PRINTF("prepare full output (check= %d):\n", checkOnly); - unsigned int offset = 0; - int numberOutputs; - int i; - unsigned int currentPos = 0; - unsigned char amount[8], totalOutputAmount[8], fees[8]; - char tmp[80]; - unsigned char outputPos = 0, changeFound = 0; - unsigned char script_version[2]; // Decred thing - - if (btchip_context_D.transactionContext.relaxed && - !btchip_context_D.transactionContext.consumeP2SH) { - if (!checkOnly) { - PRINTF("Error : Mixed inputs"); - } - goto error; - } - if (btchip_context_D.transactionContext.consumeP2SH) { - if (checkOnly) { - goto error; - } - vars.tmp.fullAmount[0] = '\0'; - vars.tmp.feesAmount[0] = '\0'; - strcpy(vars.tmp.fullAddress, "P2SH"); - return 1; - } - // Parse output, locate the change output location - os_memset(totalOutputAmount, 0, sizeof(totalOutputAmount)); - numberOutputs = btchip_context_D.currentOutput[offset++]; - PRINTF("%d outputs\n", numberOutputs); - if (numberOutputs > 3) { - if (!checkOnly) { - PRINTF("Error : Too many outputs"); - } - goto error; - } - for (i = 0; i < numberOutputs; i++) { - unsigned char nullAmount = 1; - unsigned int j; - unsigned char isOpReturn, isP2sh; - unsigned char isOpCreate, isOpCall; - - for (j = 0; j < 8; j++) { - if (btchip_context_D.currentOutput[offset + j] != 0) { - nullAmount = 0; - break; - } - } - btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); - transaction_amount_add_be(totalOutputAmount, totalOutputAmount, amount); - offset += 8; // skip amount - - btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version - - isOpReturn = btchip_output_script_is_op_return( - btchip_context_D.currentOutput + offset); - isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + - offset); - isOpCreate = btchip_output_script_is_op_create( - btchip_context_D.currentOutput + offset); - isOpCall = btchip_output_script_is_op_call( - btchip_context_D.currentOutput + offset); - PRINTF("REGULAR SCRIPT: %d\n", btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); - // Always notify OP_RETURN to the user - if (nullAmount && isOpReturn) { - if (!checkOnly) { - PRINTF("Error : Unexpected OP_RETURN"); - } - goto error; - } - if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + - offset) && - !isP2sh && !(nullAmount && isOpReturn) && - (!isOpCreate && !isOpCall)) { - if (!checkOnly) { - PRINTF("Error : Unrecognized input script"); - } - goto error; - } else if (!btchip_output_script_is_regular( - btchip_context_D.currentOutput + offset) && - !isP2sh && !(nullAmount && isOpReturn)) { - if (!checkOnly) { - PRINTF("Error : Unrecognized input script"); - } - goto error; - } - if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { - unsigned char addressOffset = - (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (os_memcmp(btchip_context_D.currentOutput + offset + - addressOffset, - btchip_context_D.tmpCtx.output.changeAddress + 1, - 20) == 0) { - if (changeFound) { - if (!checkOnly) { - PRINTF("Error : Multiple change output found"); - } - goto error; - } - changeFound = 1; - } else { - // outputPos is the real output pointer (opposed to the change address output) - outputPos = currentPos; - } - } - offset += 1 + btchip_context_D.currentOutput[offset]; - currentPos++; - } - if (btchip_context_D.tmpCtx.output.changeInitialized && !changeFound) { - if (!checkOnly) { - PRINTF("Error : change output not found"); - } - goto error; - } - if (transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - totalOutputAmount)) { - PRINTF("tx_amount: ", 8, btchip_context_D.transactionContext.transactionAmount); - PRINTF("total_amount: ", 8, totalOutputAmount); - if (!checkOnly) { - PRINTF("Error : Fees not consistent"); - } - goto error; - } - if (!checkOnly) { - // Format validation message - currentPos = 0; - offset = 1; - btchip_context_D.tmp = (unsigned char *)tmp; - for (i = 0; i < numberOutputs; i++) { - if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + 2)) { - unsigned char versionSize; - int addressOffset; - unsigned char address[22]; - unsigned short version; - - btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); - offset += 8; // skip amount - - btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version - - if (btchip_output_script_is_regular( - btchip_context_D.currentOutput + offset)) { - addressOffset = offset + 4; - version = btchip_context_D.payToAddressVersion; - } else { - addressOffset = offset + 3; - version = btchip_context_D.payToScriptHashVersion; - } - if (version > 255) { - versionSize = 2; - address[0] = (version >> 8); - address[1] = version; - } else { - versionSize = 1; - address[0] = version; - } - os_memmove(address + versionSize, - btchip_context_D.currentOutput + addressOffset, - 20); - - // if we're processing the real output (not the change one) - if (currentPos == outputPos) { - unsigned short textSize = 0; - - // Prepare address - textSize = btchip_public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)tmp, - sizeof(tmp), version, 1); - tmp[textSize] = '\0'; - - strcpy(vars.tmp.fullAddress, tmp); - - // Prepare amount - PRINTF("prepare amount\n"); - - os_memmove(vars.tmp.fullAmount, - btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); - vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = - ' '; - btchip_context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - btchip_context_D.shortCoinIdLength + - 1); - textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp - .fullAmount[textSize + - btchip_context_D.shortCoinIdLength + 1] = - '\0'; - - // prepare fee display - PRINTF("prepare fee display\n"); - os_memmove(vars.tmp.feesAmount, - btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); - vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = - ' '; - btchip_context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - btchip_context_D.shortCoinIdLength + - 1); - textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp - .feesAmount[textSize + - btchip_context_D.shortCoinIdLength + 1] = - '\0'; - break; - } - } else { - // amount + version - offset += 8 + 2; - } - offset += 1 + btchip_context_D.currentOutput[offset]; - currentPos++; - } - } - return 1; -error: - return 0; -} - -#define HASH_LENGTH 4 -uint8_t prepare_message_signature() { - uint8_t buffer[32]; - - cx_hash(&btchip_context_D.transactionHashWitness.header, CX_LAST, - vars.tmp.fullAmount, 0, buffer, 32); - - snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H...%.*H", - 8, buffer, 8, buffer + 32 - 8); - return 1; -} - -unsigned int btchip_bagl_confirm_full_output() { - if (!prepare_full_output(0)) { - return 0; - } - -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 4; - UX_DISPLAY(ui_verify_nanos, ui_verify_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, ux_confirm_full_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 - return 1; -} - -unsigned int btchip_bagl_confirm_single_output() { -// TODO : remove when supporting multi output - if (!prepare_single_output()) { - return 0; - } - - snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + - 1); - -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 3; - UX_DISPLAY(ui_verify_output_nanos, ui_verify_output_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, ux_confirm_single_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 - return 1; -} - -unsigned int btchip_bagl_finalize_tx() { - if (!prepare_fees()) { - return 0; - } - -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 2; - UX_DISPLAY(ui_finalize_nanos, ui_finalize_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, ux_finalize_flow, NULL); -#endif // TARGET_NANOX - return 1; -} - -void btchip_bagl_confirm_message_signature() { - if (!prepare_message_signature()) { - return; - } - -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 2; - UX_DISPLAY(ui_verify_message_signature_nanos, ui_verify_message_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, ux_sign_flow, NULL); -#endif // TARGET_NANOX -} - -void btchip_bagl_request_change_path_approval(unsigned char* change_path) -{ - bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); -#if defined(TARGET_NANOS) - // append and prepend a white space to the address - ux_step = 0; - ux_step_count = 4; - UX_DISPLAY(ui_request_change_path_approval_nanos, ui_request_change_path_approval_nanos_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, ux_request_change_path_approval_flow, NULL); -#endif // #if TARGET_ID -} - void app_exit(void) { BEGIN_TRY_L(exit) { TRY_L(exit) { diff --git a/src/ui/transaction/ui_transaction.h b/src/ui/transaction/ui_transaction.h new file mode 100644 index 0000000..1c22ff1 --- /dev/null +++ b/src/ui/transaction/ui_transaction.h @@ -0,0 +1,23 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#pragma once + +unsigned int btchip_bagl_confirm_full_output(void); +unsigned int btchip_bagl_confirm_single_output(void); +unsigned int btchip_bagl_finalize_tx(void); +void btchip_bagl_confirm_message_signature(void); +void btchip_bagl_request_change_path_approval(unsigned char* change_path); \ No newline at end of file diff --git a/src/ui/transaction/ui_transaction_bagl.c b/src/ui/transaction/ui_transaction_bagl.c new file mode 100644 index 0000000..89f5434 --- /dev/null +++ b/src/ui/transaction/ui_transaction_bagl.c @@ -0,0 +1,637 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#ifdef HAVE_BAGL +#include "ui_transaction.h" +#include "ui_shared.h" +#include "os.h" +#include "os_io_seproxyhal.h" +#include "ux.h" +#include "string.h" +#include "btchip_internal.h" + +#if defined(TARGET_NANOS) + +const bagl_element_t ui_request_change_path_approval_nanos[] = { + UI_NANOS_BACKGROUND(), + + UI_NANOS_TEXT(1, 0, 22, 128, "Warning !", BAGL_FONT_OPEN_SANS_LIGHT_16px), + + UI_NANOS_TEXT(2, 0, 12, 128, "The change path", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(2, 0, 26, 128, "is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(3, 0, 12, 128, "Change path", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; + +unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t *element) { + if (element->component.userid > 0) { + unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); + if (display) { + if (element->component.userid & 0x80) { + ux_loop_over_curr_element = 1; + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + } + } + return display; + } + return 1; +} + +unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); + +const bagl_element_t ui_verify_nanos[] = { + UI_NANOS_BACKGROUND(), + UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(1, 0, 26, 128, "transaction", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(2, 0, 12, 128, "Amount", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(4, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(4, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) + +}; +unsigned int ui_verify_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); + +const bagl_element_t ui_verify_output_nanos[] = { + + UI_NANOS_BACKGROUND(), + UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(1, 0, 26, 128, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(2, 0, 12, 128, "Amount", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; + +unsigned int ui_verify_output_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); + +const bagl_element_t ui_finalize_nanos[] = { + UI_NANOS_BACKGROUND(), + UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(1, 0, 26, 128, "transaction", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(2, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) + + + /* TODO + {{BAGL_LABELINE , 0x02, 0, 12, 128, 12, 0, 0, 0 , + COLOR_WHITE, COLOR_BLACK, + BAGL_FONT_OPEN_SANS_REGULAR_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Amount", + 0, 0, 0, NULL, NULL, NULL }, + {{BAGL_LABELINE , 0x02, 23, 26, 82, 12, 0x80|10, + 0, 0 , COLOR_WHITE, COLOR_BLACK, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 26 }, + vars.tmp.fullAmount, 0, 0, 0, NULL, NULL, NULL }, + */ +}; +unsigned int ui_finalize_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); + +// display or not according to step, and adjust delay +unsigned int ui_verify_prepro(const bagl_element_t *element) { + if (element->component.userid > 0) { + unsigned int display = (ux_step == element->component.userid - 1); + if (display) { + switch (element->component.userid) { + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + case 4: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; + } + } + return display; + } + return 1; +} + +unsigned int ui_verify_output_prepro(const bagl_element_t *element) { + if (element->component.userid > 0) { + unsigned int display = (ux_step == element->component.userid - 1); + if (display) { + switch (element->component.userid) { + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; + } + } + return display; + } + return 1; +} + +unsigned int ui_finalize_prepro(const bagl_element_t *element) { + if (element->component.userid > 0) { + unsigned int display = (ux_step == element->component.userid - 1); + if (display) { + switch (element->component.userid) { + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; + } + } + return display; + } + return 1; +} + +const bagl_element_t ui_verify_message_signature_nanos[] = { + UI_NANOS_BACKGROUND(), + UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), + UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), + UI_NANOS_TEXT(1, 0, 12, 128, "Sign the", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_TEXT(1, 0, 26, 128, "message", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + + UI_NANOS_TEXT(2, 0, 12, 128, "Message hash", BAGL_FONT_OPEN_SANS_REGULAR_11px), + UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) +}; +unsigned int +ui_verify_message_signature_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); + +unsigned int ui_verify_message_prepro(const bagl_element_t *element) { + if (element->component.userid > 0) { + unsigned int display = (ux_step == element->component.userid - 1); + if (display) { + switch (element->component.userid) { + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL(MAX( + 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; + } + } + return display; + } + return 1; +} + +unsigned int ui_verify_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { + UNUSED(button_mask_counter); + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; + + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; + } + return 0; +} + +unsigned int ui_verify_output_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { + UNUSED(button_mask_counter); + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; + + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; + } + return 0; +} + +unsigned int ui_finalize_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { + UNUSED(button_mask_counter); + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; + + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; + } + return 0; +} + +unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { + UNUSED(button_mask_counter); + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_message_signature_verify_cancel(NULL); + break; + + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_message_signature_verify_ok(NULL); + break; + } + return 0; +} + + unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) +{ + UNUSED(button_mask_counter); + if (ux_step == 3) + { + switch (button_mask) + { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; + } + } + else + { + if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) + { + // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) + if(ux_loop_over_curr_element) { + ux_loop_over_curr_element = 0; + ux.callback_interval_ms = 0; + } + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); + } + } + return 0; +} + +#endif // #if defined(TARGET_NANOS) + +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB( + ux_sign_flow_1_step, + pnn, + { + &C_icon_certificate, + "Sign", + "message", + }); +UX_STEP_NOCB( + ux_sign_flow_2_step, + bnnn_paging, + { + .title = "Message hash", + .text = vars.tmp.fullAddress, + }); +UX_STEP_VALID( + ux_sign_flow_3_step, + pbb, + io_seproxyhal_touch_message_signature_verify_ok(NULL), + { + &C_icon_validate_14, + "Sign", + "message", + }); +UX_STEP_VALID( + ux_sign_flow_4_step, + pbb, + io_seproxyhal_touch_message_signature_verify_cancel(NULL), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); + +UX_FLOW(ux_sign_flow, + &ux_sign_flow_1_step, + &ux_sign_flow_2_step, + &ux_sign_flow_3_step, + &ux_sign_flow_4_step +); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_NOCB(ux_confirm_full_flow_1_step, + pnn, + { + &C_icon_eye, + "Review", + "transaction", + }); +UX_STEP_NOCB( + ux_confirm_full_flow_2_step, + bnnn_paging, + { + .title = "Amount", + .text = vars.tmp.fullAmount + }); +UX_STEP_NOCB( + ux_confirm_full_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB( + ux_confirm_full_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID( + ux_confirm_full_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + "and send", + }); +UX_STEP_VALID( + ux_confirm_full_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); +// confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress / Fees: feesAmount +UX_FLOW(ux_confirm_full_flow, + &ux_confirm_full_flow_1_step, + &ux_confirm_full_flow_2_step, + &ux_confirm_full_flow_3_step, + &ux_confirm_full_flow_4_step, + &ux_confirm_full_flow_5_step, + &ux_confirm_full_flow_6_step +); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_NOCB( + ux_confirm_single_flow_1_step, + pnn, + { + &C_icon_eye, + "Review", + "transaction" + }); +UX_STEP_NOCB( + ux_confirm_single_flow_2_step, + bnnn_paging, + { + .title = "Amount", + .text = vars.tmp.fullAmount, + }); +UX_STEP_NOCB( + ux_confirm_single_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB( + ux_confirm_single_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID( + ux_confirm_single_flow_5_step, + pb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + }); +UX_STEP_VALID( + ux_confirm_single_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); +// confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: fullAddress +UX_FLOW(ux_confirm_single_flow, + &ux_confirm_single_flow_1_step, + &ux_confirm_single_flow_2_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_4_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step +); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_NOCB( + ux_finalize_flow_1_step, + pnn, + { + &C_icon_eye, + "Review", + "transaction" + }); +UX_STEP_NOCB( + ux_finalize_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID( + ux_finalize_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + "and send" + }); +UX_STEP_VALID( + ux_finalize_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); +// finalize: confirm transaction / Fees: feesAmount +UX_FLOW(ux_finalize_flow, + &ux_finalize_flow_1_step, + &ux_finalize_flow_4_step, + &ux_finalize_flow_5_step, + &ux_finalize_flow_6_step +); + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB( + ux_request_change_path_approval_flow_1_step, + pbb, + { + &C_icon_eye, + "The change path", + "is unusual", + }); +UX_STEP_NOCB( + ux_request_change_path_approval_flow_2_step, + bnnn_paging, + { + .title = "Change path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_VALID( + ux_request_change_path_approval_flow_3_step, + pbb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_VALID( + ux_request_change_path_approval_flow_4_step, + pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); + +UX_FLOW(ux_request_change_path_approval_flow, + &ux_request_change_path_approval_flow_1_step, + &ux_request_change_path_approval_flow_2_step, + &ux_request_change_path_approval_flow_3_step, + &ux_request_change_path_approval_flow_4_step +); + +#endif // TARGET_NANOX || TARGET_NANOS2 + + +unsigned int btchip_bagl_confirm_full_output() { + if (!prepare_full_output(0)) { + return 0; + } + +#if defined(TARGET_NANOS) + ux_step = 0; + ux_step_count = 4; + UX_DISPLAY(ui_verify_nanos, ui_verify_prepro); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, ux_confirm_full_flow, NULL); +#endif // TARGET_NANOX || TARGET_NANOS2 + return 1; +} + +unsigned int btchip_bagl_confirm_single_output() { +// TODO : remove when supporting multi output + if (!prepare_single_output()) { + return 0; + } + + snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + + 1); + +#if defined(TARGET_NANOS) + ux_step = 0; + ux_step_count = 3; + UX_DISPLAY(ui_verify_output_nanos, ui_verify_output_prepro); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, ux_confirm_single_flow, NULL); +#endif // TARGET_NANOX || TARGET_NANOS2 + return 1; +} + +unsigned int btchip_bagl_finalize_tx() { + if (!prepare_fees()) { + return 0; + } + +#if defined(TARGET_NANOS) + ux_step = 0; + ux_step_count = 2; + UX_DISPLAY(ui_finalize_nanos, ui_finalize_prepro); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, ux_finalize_flow, NULL); +#endif // TARGET_NANOX + return 1; +} + +void btchip_bagl_confirm_message_signature() { + if (!prepare_message_signature()) { + return; + } + +#if defined(TARGET_NANOS) + ux_step = 0; + ux_step_count = 2; + UX_DISPLAY(ui_verify_message_signature_nanos, ui_verify_message_prepro); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, ux_sign_flow, NULL); +#endif // TARGET_NANOX +} + +void btchip_bagl_request_change_path_approval(unsigned char* change_path) +{ + bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); +#if defined(TARGET_NANOS) + // append and prepend a white space to the address + ux_step = 0; + ux_step_count = 4; + UX_DISPLAY(ui_request_change_path_approval_nanos, ui_request_change_path_approval_nanos_prepro); +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + ux_flow_init(0, ux_request_change_path_approval_flow, NULL); +#endif // #if TARGET_ID +} + +#endif \ No newline at end of file diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 34e01d5..351a0cc 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -15,7 +15,12 @@ * limitations under the License. ********************************************************************************/ #include "ui_shared.h" +#include "btchip_transaction.h" #include "btchip_bagl_extensions.h" +#include "btchip_public_ram_variables.h" +#include "btchip_helpers.h" +#include "btchip_bcd.h" +#include "ui_main_menu.h" unsigned int ux_step; unsigned int ux_step_count; @@ -43,3 +48,406 @@ unsigned int io_seproxyhal_touch_display_ok(const void* e){ #endif return 0; // DO NOT REDRAW THE BUTTON } + +unsigned int io_seproxyhal_touch_verify_cancel(const void *e) { + UNUSED(e); + + // user denied the transaction, tell the USB side + if (!btchip_bagl_user_action(0)) { + // redraw ui + ui_idle(); + } + return 0; // DO NOT REDRAW THE BUTTON +} + +unsigned int io_seproxyhal_touch_verify_ok(const void *e) { + UNUSED(e); + // user accepted the transaction, tell the USB side + if (!btchip_bagl_user_action(1)) { + // redraw ui + ui_idle(); + } + return 0; // DO NOT REDRAW THE BUTTON +} + +unsigned int +io_seproxyhal_touch_message_signature_verify_cancel(const void *e) { + UNUSED(e); + // user denied the transaction, tell the USB side + btchip_bagl_user_action_message_signing(0); + // redraw ui + ui_idle(); + return 0; // DO NOT REDRAW THE BUTTON +} + +unsigned int +io_seproxyhal_touch_message_signature_verify_ok(const void *e) { + UNUSED(e); + // user accepted the transaction, tell the USB side + btchip_bagl_user_action_message_signing(1); + // redraw ui + ui_idle(); + return 0; // DO NOT REDRAW THE BUTTON +} + +unsigned int io_seproxyhal_touch_display_token_cancel(const void *e) { + UNUSED(e); + // revoke previous valid token if there was one + btchip_context_D.has_valid_token = false; + // user denied the token, tell the USB side + btchip_bagl_user_action_display(0); + // redraw ui + ui_idle(); + return 0; // DO NOT REDRAW THE BUTTON +} + +unsigned int io_seproxyhal_touch_display_token_ok(const void *e) { + UNUSED(e); + // Set the valid token flag + btchip_context_D.has_valid_token = true; + // user approved the token, tell the USB side + btchip_bagl_user_action_display(1); + // redraw ui + ui_idle(); + return 0; // DO NOT REDRAW THE BUTTON +} + + +uint8_t prepare_fees() { + if (btchip_context_D.transactionContext.relaxed) { + memmove(vars.tmp.feesAmount, "UNKNOWN", 7); + vars.tmp.feesAmount[7] = '\0'; + } else { + unsigned char fees[8]; + unsigned short textSize; + if (transaction_amount_sub_be( + fees, btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.totalOutputAmount)) { + PRINTF("Fees: %.*H\n", 8, fees); + PRINTF("transactionAmount:: %.*H\n", 8, btchip_context_D.transactionContext.transactionAmount); + PRINTF("totalOutputAmount: %.*H\n", 8, btchip_context_D.totalOutputAmount); + PRINTF("Error : Fees not consistent"); + goto error; + } + memmove(vars.tmp.feesAmount, btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); + vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; + btchip_context_D.tmp = + (unsigned char *)(vars.tmp.feesAmount + + btchip_context_D.shortCoinIdLength + 1); + textSize = btchip_convert_hex_amount_to_displayable(fees); + vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = + '\0'; + } + return 1; +error: + return 0; +} + +uint8_t prepare_message_signature() { + uint8_t buffer[32]; + + cx_hash((cx_hash_t *)&btchip_context_D.transactionHashWitness.header, CX_LAST, + (const unsigned char *) vars.tmp.fullAmount, 0, buffer, 32); + + snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H...%.*H", + 8, buffer, 8, buffer + 32 - 8); + return 1; +} + +uint8_t prepare_single_output() { + // TODO : special display for OP_RETURN + unsigned char amount[8]; + char tmp[80]; + unsigned int offset = 0; + unsigned char versionSize; + int addressOffset; + unsigned char address[22]; + unsigned short version; // addr prefix, or net id + unsigned short textSize; + unsigned char script_version[2]; // Decred thing + + vars.tmp.fullAddress[0] = '\0'; + btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); + offset += 8; + + btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); + offset += 2; + + PRINTF("amount: %.*H\n", 8, amount); + + if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + + offset)) { + strcpy(vars.tmp.fullAddress, "OP_RETURN"); + } + else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + + offset)) { + addressOffset = offset + 4; + version = btchip_context_D.payToAddressVersion; + } + else { + addressOffset = offset + 3; + version = btchip_context_D.payToScriptHashVersion; + } + if (vars.tmp.fullAddress[0] == 0) { + + if (version > 255) { + versionSize = 2; + address[0] = (version >> 8); + address[1] = version; + } else { + versionSize = 1; + address[0] = version; + } + memmove(address + versionSize, + btchip_context_D.currentOutput + addressOffset, 20); + + // Prepare address + textSize = btchip_public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)tmp, + sizeof(tmp), version, 1); + tmp[textSize] = '\0'; + + strcpy(vars.tmp.fullAddress, tmp); + } + + // Prepare amount + + memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); + vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; + btchip_context_D.tmp = + (unsigned char *)(vars.tmp.fullAmount + + btchip_context_D.shortCoinIdLength + 1); + textSize = btchip_convert_hex_amount_to_displayable(amount); + vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = + '\0'; + + return 1; +} + +uint8_t prepare_full_output(uint8_t checkOnly) { + PRINTF("prepare full output (check= %d):\n", checkOnly); + unsigned int offset = 0; + int numberOutputs; + int i; + unsigned int currentPos = 0; + unsigned char amount[8], totalOutputAmount[8], fees[8]; + char tmp[80]; + unsigned char outputPos = 0, changeFound = 0; + unsigned char script_version[2]; // Decred thing + + if (btchip_context_D.transactionContext.relaxed && + !btchip_context_D.transactionContext.consumeP2SH) { + if (!checkOnly) { + PRINTF("Error : Mixed inputs"); + } + goto error; + } + if (btchip_context_D.transactionContext.consumeP2SH) { + if (checkOnly) { + goto error; + } + vars.tmp.fullAmount[0] = '\0'; + vars.tmp.feesAmount[0] = '\0'; + strcpy(vars.tmp.fullAddress, "P2SH"); + return 1; + } + // Parse output, locate the change output location + explicit_bzero(totalOutputAmount, sizeof(totalOutputAmount)); + numberOutputs = btchip_context_D.currentOutput[offset++]; + PRINTF("%d outputs\n", numberOutputs); + if (numberOutputs > 3) { + if (!checkOnly) { + PRINTF("Error : Too many outputs"); + } + goto error; + } + for (i = 0; i < numberOutputs; i++) { + unsigned char nullAmount = 1; + unsigned int j; + unsigned char isOpReturn, isP2sh; + unsigned char isOpCreate, isOpCall; + + for (j = 0; j < 8; j++) { + if (btchip_context_D.currentOutput[offset + j] != 0) { + nullAmount = 0; + break; + } + } + btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); + transaction_amount_add_be(totalOutputAmount, totalOutputAmount, amount); + offset += 8; // skip amount + + btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); + offset += 2; // skip script_version + + isOpReturn = btchip_output_script_is_op_return( + btchip_context_D.currentOutput + offset); + isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + + offset); + isOpCreate = btchip_output_script_is_op_create( + btchip_context_D.currentOutput + offset); + isOpCall = btchip_output_script_is_op_call( + btchip_context_D.currentOutput + offset); + PRINTF("REGULAR SCRIPT: %d\n", btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); + // Always notify OP_RETURN to the user + if (nullAmount && isOpReturn) { + if (!checkOnly) { + PRINTF("Error : Unexpected OP_RETURN"); + } + goto error; + } + if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + + offset) && + !isP2sh && !(nullAmount && isOpReturn) && + (!isOpCreate && !isOpCall)) { + if (!checkOnly) { + PRINTF("Error : Unrecognized input script"); + } + goto error; + } else if (!btchip_output_script_is_regular( + btchip_context_D.currentOutput + offset) && + !isP2sh && !(nullAmount && isOpReturn)) { + if (!checkOnly) { + PRINTF("Error : Unrecognized input script"); + } + goto error; + } + if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { + unsigned char addressOffset = + (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH + : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (memcmp(btchip_context_D.currentOutput + offset + + addressOffset, + btchip_context_D.tmpCtx.output.changeAddress + 1, + 20) == 0) { + if (changeFound) { + if (!checkOnly) { + PRINTF("Error : Multiple change output found"); + } + goto error; + } + changeFound = 1; + } else { + // outputPos is the real output pointer (opposed to the change address output) + outputPos = currentPos; + } + } + offset += 1 + btchip_context_D.currentOutput[offset]; + currentPos++; + } + if (btchip_context_D.tmpCtx.output.changeInitialized && !changeFound) { + if (!checkOnly) { + PRINTF("Error : change output not found"); + } + goto error; + } + if (transaction_amount_sub_be( + fees, btchip_context_D.transactionContext.transactionAmount, + totalOutputAmount)) { + PRINTF("tx_amount: ", 8, btchip_context_D.transactionContext.transactionAmount); + PRINTF("total_amount: ", 8, totalOutputAmount); + if (!checkOnly) { + PRINTF("Error : Fees not consistent"); + } + goto error; + } + if (!checkOnly) { + // Format validation message + currentPos = 0; + offset = 1; + btchip_context_D.tmp = (unsigned char *)tmp; + for (i = 0; i < numberOutputs; i++) { + if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + 2)) { + unsigned char versionSize; + int addressOffset; + unsigned char address[22]; + unsigned short version; + + btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); + offset += 8; // skip amount + + btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); + offset += 2; // skip script_version + + if (btchip_output_script_is_regular( + btchip_context_D.currentOutput + offset)) { + addressOffset = offset + 4; + version = btchip_context_D.payToAddressVersion; + } else { + addressOffset = offset + 3; + version = btchip_context_D.payToScriptHashVersion; + } + if (version > 255) { + versionSize = 2; + address[0] = (version >> 8); + address[1] = version; + } else { + versionSize = 1; + address[0] = version; + } + memmove(address + versionSize, + btchip_context_D.currentOutput + addressOffset, + 20); + + // if we're processing the real output (not the change one) + if (currentPos == outputPos) { + unsigned short textSize = 0; + + // Prepare address + textSize = btchip_public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)tmp, + sizeof(tmp), version, 1); + tmp[textSize] = '\0'; + + strcpy(vars.tmp.fullAddress, tmp); + + // Prepare amount + PRINTF("prepare amount\n"); + + memmove(vars.tmp.fullAmount, + btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); + vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = + ' '; + btchip_context_D.tmp = + (unsigned char *)(vars.tmp.fullAmount + + btchip_context_D.shortCoinIdLength + + 1); + textSize = btchip_convert_hex_amount_to_displayable(amount); + vars.tmp + .fullAmount[textSize + + btchip_context_D.shortCoinIdLength + 1] = + '\0'; + + // prepare fee display + PRINTF("prepare fee display\n"); + memmove(vars.tmp.feesAmount, + btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); + vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = + ' '; + btchip_context_D.tmp = + (unsigned char *)(vars.tmp.feesAmount + + btchip_context_D.shortCoinIdLength + + 1); + textSize = btchip_convert_hex_amount_to_displayable(fees); + vars.tmp + .feesAmount[textSize + + btchip_context_D.shortCoinIdLength + 1] = + '\0'; + break; + } + } else { + // amount + version + offset += 8 + 2; + } + offset += 1 + btchip_context_D.currentOutput[offset]; + currentPos++; + } + } + return 1; +error: + return 0; +} diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index e22be98..0545d33 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -62,3 +62,15 @@ extern uint8_t ux_loop_over_curr_element; unsigned int io_seproxyhal_touch_display_cancel(const void* e); unsigned int io_seproxyhal_touch_display_ok(const void* e); + +unsigned int io_seproxyhal_touch_verify_cancel(const void *e); +unsigned int io_seproxyhal_touch_verify_ok(const void *e); +unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const void *e); +unsigned int io_seproxyhal_touch_message_signature_verify_ok(const void *e); +unsigned int io_seproxyhal_touch_display_token_cancel(const void *e); +unsigned int io_seproxyhal_touch_display_token_ok(const void *e); + +uint8_t prepare_fees(); +uint8_t prepare_message_signature(); +uint8_t prepare_single_output(); +uint8_t prepare_full_output(uint8_t checkOnly); \ No newline at end of file From ba0b44f91e4f3aaf7917d711b6373e94eeea243c Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 1 Dec 2022 20:24:17 +0100 Subject: [PATCH 13/41] Add Stax transaction screens. --- src/ui/transaction/ui_transaction_nbgl.c | 225 +++++++++++++++++++++++ src/ui/ui_shared.c | 17 +- 2 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 src/ui/transaction/ui_transaction_nbgl.c diff --git a/src/ui/transaction/ui_transaction_nbgl.c b/src/ui/transaction/ui_transaction_nbgl.c new file mode 100644 index 0000000..cce3316 --- /dev/null +++ b/src/ui/transaction/ui_transaction_nbgl.c @@ -0,0 +1,225 @@ +/******************************************************************************* +* Ledger App - Decred Wallet +* (c) 2022 Ledger +* +* 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. +********************************************************************************/ +#ifdef HAVE_NBGL +#include // bool +#include // memset + +#include "os.h" +#include "os_io_seproxyhal.h" +#include "ux.h" +#include "nbgl_use_case.h" + +#include "ui_main_menu.h" +#include "ui_transaction.h" +#include "ui_shared.h" +#include "btchip_internal.h" + +typedef enum { + TX_TYPE_SINGLE_OUTPUT = 0, + TX_TYPE_FULL_REVIEW, + TX_TYPE_FINALIZE, + TX_TYPE_SIGN_MESSAGE, +} transaction_type_t; + +typedef struct { + char* reviewStart; + char* reviewCancel; + char* finishOk; + char* finishCancel; + char* choiceCancel; + char* choiceGoBack; +} messages_t; + +static nbgl_layoutTagValueList_t pairList; +static nbgl_layoutTagValue_t pairs[4]; +static nbgl_pageInfoLongPress_t infoLongPress; +static transaction_type_t txType; +static messages_t msgs; +static char genericText[70]; +static bool reviewStarted; + +static void reviewChoice(bool confirm); +static void rejectChoice(bool confirm); +static void rejectUseCaseChoice(void); +static void displayTransaction(void); +static void reviewStart(void); + +static void rejectChoice(bool confirm) { + if (confirm){ + nbgl_useCaseStatus(msgs.finishCancel,true,ui_idle); + txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_cancel(NULL) : + io_seproxyhal_touch_verify_cancel(NULL); + } + else{ + if(reviewStarted) + { + displayTransaction(); + } + else + { + reviewStart(); + } + } +} + +static void reviewChoice(bool confirm) { + if (confirm) { + if(txType != TX_TYPE_SINGLE_OUTPUT) + { + nbgl_useCaseStatus(msgs.finishOk,true,ui_idle); + } + txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_ok(NULL) : + io_seproxyhal_touch_verify_ok(NULL); + } + else { + rejectUseCaseChoice(); + } +} + +static void rejectUseCaseChoice(void) +{ + nbgl_useCaseChoice(msgs.choiceCancel,NULL,"Yes, cancel",msgs.choiceGoBack,rejectChoice); +} + +static void displayTransaction(void) { + reviewStarted = true; + nbgl_useCaseStaticReview(&pairList, &infoLongPress, msgs.reviewCancel, reviewChoice); +} + +static void reviewStart(void) { + explicit_bzero(pairs, sizeof(pairs)); + explicit_bzero(&infoLongPress, sizeof(infoLongPress)); + + msgs.reviewStart = "Review\ntransaction"; + msgs.reviewCancel = "Cancel transaction"; + msgs.choiceCancel = "Cancel transaction ?"; + msgs.choiceGoBack = "Go back to transaction"; + msgs.finishOk = "TRANSACTION\nSIGNED"; + msgs.finishCancel = "Transaction rejected"; + + infoLongPress.text = "Accept and send"; + infoLongPress.longPressText = "Hold to accept"; + infoLongPress.icon = NULL;//&C_decred_icon_64px; + + pairs[0].item = "Amount"; + pairs[0].value = vars.tmp.fullAmount; + pairs[1].item = "To"; + pairs[1].value = vars.tmp.fullAddress; + pairs[2].item = "Fees"; + pairs[2].value = vars.tmp.feesAmount; + pairList.nbPairs = 3; + pairList.pairs = (nbgl_layoutTagValue_t*)pairs; + + switch(txType){ + case TX_TYPE_SINGLE_OUTPUT: + pairList.nbPairs = 2; + explicit_bzero(genericText, sizeof(genericText)); + snprintf(genericText, + sizeof(genericText), + "Review output\n%d of %d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1, + btchip_context_D.totalOutputs); + msgs.reviewStart = genericText; + infoLongPress.text = "Approve output"; + infoLongPress.longPressText = "Hold to approve"; + break; + case TX_TYPE_FINALIZE: + pairs[0].item = "Fees"; + pairs[0].value = vars.tmp.feesAmount; + pairList.nbPairs = 1; + msgs.reviewStart = "Finalize\n transaction"; + break; + case TX_TYPE_SIGN_MESSAGE: + pairs[0].item = "Message Hash"; + pairs[0].value = vars.tmp.fullAddress; + pairList.nbPairs = 1; + msgs.reviewStart = "Sign\nMessage"; + msgs.reviewCancel = "Cancel signature"; + msgs.choiceCancel = "Cancel signature ?"; + msgs.choiceGoBack = "Go back to signature"; + msgs.finishOk = "MESSAGE SIGNED"; + msgs.finishCancel = "SIGNATURE\nCANCELLED"; + infoLongPress.text = "Sign message"; + infoLongPress.longPressText = "Hold to sign"; + break; + case TX_TYPE_FULL_REVIEW: + default: + break; + } + + reviewStarted = false; + nbgl_useCaseReviewStart(NULL/*&C_decred_icon_64px*/, msgs.reviewStart, NULL, + msgs.reviewCancel, displayTransaction, rejectUseCaseChoice); +} + +unsigned int btchip_bagl_confirm_full_output() { + txType = TX_TYPE_FULL_REVIEW; + if (!prepare_full_output(0)) { + return 0; + } + reviewStart(); + return 1; +} + +unsigned int btchip_bagl_finalize_tx() { + txType = TX_TYPE_FINALIZE; + if (!prepare_fees()) { + return 0; + } + reviewStart(); + return 1; +} + +void btchip_bagl_confirm_message_signature() { + txType = TX_TYPE_SIGN_MESSAGE; + if (!prepare_message_signature()) { + + return; + } + reviewStart(); +} + +unsigned int btchip_bagl_confirm_single_output() { + txType = TX_TYPE_SINGLE_OUTPUT; + if (!prepare_single_output()) { + return 0; + } + reviewStart(); + return 1; +} + +static void changePathWarningChoice(bool reject) { + if (reject) { + io_seproxyhal_touch_display_cancel(NULL); + nbgl_useCaseStatus("Transaction rejected",false,ui_idle); + } + else { + io_seproxyhal_touch_display_ok(NULL); + } +} + +void btchip_bagl_request_change_path_approval(unsigned char* change_path) +{ + bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); + explicit_bzero(genericText, sizeof(genericText)); + snprintf(genericText, + sizeof(genericText), + "WARNING !\nThe change path is\nunusual :\n%s", + vars.tmp_warning.derivation_path); + nbgl_useCaseChoice(genericText,"Reject if you're not sure","Reject","Continue",changePathWarningChoice); +} +#endif diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 351a0cc..4e82f6c 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -31,8 +31,8 @@ unsigned int io_seproxyhal_touch_display_cancel(const void* e){ UNUSED(e); // user denied the transaction, tell the USB side btchip_bagl_user_action_display(0); - // redraw ui #ifndef HAVE_NBGL + // redraw ui ui_idle(); #endif return 0; // DO NOT REDRAW THE BUTTON @@ -42,8 +42,8 @@ unsigned int io_seproxyhal_touch_display_ok(const void* e){ UNUSED(e); // user accepted the transaction, tell the USB side btchip_bagl_user_action_display(1); - // redraw ui #ifndef HAVE_NBGL + // redraw ui ui_idle(); #endif return 0; // DO NOT REDRAW THE BUTTON @@ -54,8 +54,10 @@ unsigned int io_seproxyhal_touch_verify_cancel(const void *e) { // user denied the transaction, tell the USB side if (!btchip_bagl_user_action(0)) { +#ifndef HAVE_NBGL // redraw ui ui_idle(); +#endif } return 0; // DO NOT REDRAW THE BUTTON } @@ -64,8 +66,10 @@ unsigned int io_seproxyhal_touch_verify_ok(const void *e) { UNUSED(e); // user accepted the transaction, tell the USB side if (!btchip_bagl_user_action(1)) { +#ifndef HAVE_NBGL // redraw ui ui_idle(); +#endif } return 0; // DO NOT REDRAW THE BUTTON } @@ -75,8 +79,10 @@ io_seproxyhal_touch_message_signature_verify_cancel(const void *e) { UNUSED(e); // user denied the transaction, tell the USB side btchip_bagl_user_action_message_signing(0); +#ifndef HAVE_NBGL // redraw ui ui_idle(); +#endif return 0; // DO NOT REDRAW THE BUTTON } @@ -85,8 +91,10 @@ io_seproxyhal_touch_message_signature_verify_ok(const void *e) { UNUSED(e); // user accepted the transaction, tell the USB side btchip_bagl_user_action_message_signing(1); +#ifndef HAVE_NBGL // redraw ui ui_idle(); +#endif return 0; // DO NOT REDRAW THE BUTTON } @@ -150,8 +158,13 @@ uint8_t prepare_message_signature() { cx_hash((cx_hash_t *)&btchip_context_D.transactionHashWitness.header, CX_LAST, (const unsigned char *) vars.tmp.fullAmount, 0, buffer, 32); +#ifdef HAVE_NBGL + snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H", + 32, buffer); +#else snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H...%.*H", 8, buffer, 8, buffer + 32 - 8); +#endif return 1; } From 983ce1a96832ab29d829357c3bdf863aca39ad7e Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 5 Dec 2022 10:54:54 +0100 Subject: [PATCH 14/41] Rename UX transaction functions. --- src/btchip_apdu_hash_input_finalize_full.c | 12 ++++++------ src/btchip_apdu_sign_message.c | 2 +- src/ui/transaction/ui_transaction.h | 10 +++++----- src/ui/transaction/ui_transaction_bagl.c | 10 +++++----- src/ui/transaction/ui_transaction_nbgl.c | 10 +++++----- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index d126374..0131339 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -277,7 +277,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( if(bip44_derivation_guard(transactionSummary->summarydata.keyPath, true)) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_context_D.outputParsingState = BTCHIP_BIP44_CHANGE_PATH_VALIDATION; - btchip_bagl_request_change_path_approval(transactionSummary->summarydata.keyPath); + ui_tx_request_change_path_approval(transactionSummary->summarydata.keyPath); } goto return_OK; @@ -428,15 +428,15 @@ unsigned short btchip_apdu_hash_input_finalize_full() { } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { PRINTF("BAGL finalize tx:\n"); - status = btchip_bagl_finalize_tx(); + status = ui_tx_finalize(); } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_HANDLE_LEGACY) { PRINTF("BAGL confirm output legacy:\n"); - status = btchip_bagl_confirm_full_output(); + status = ui_tx_confirm_full_output(); } else { PRINTF("BAGL confirm single output:\n"); - status = btchip_bagl_confirm_single_output(); + status = ui_tx_confirm_single_output(); } if (!status) { btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; @@ -475,7 +475,7 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) ; if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { - if (!btchip_bagl_confirm_single_output()) { + if (!ui_tx_confirm_single_output()) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_INCORRECT_DATA; @@ -494,7 +494,7 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { BTCHIP_OUTPUT_PARSING_OUTPUT) && (btchip_context_D.remainingOutputs == 0)) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; - if (!btchip_bagl_finalize_tx()) { + if (!ui_tx_finalize()) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NONE; btchip_context_D.transactionContext.transactionState = diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 035b5ae..86296aa 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -232,7 +232,7 @@ unsigned short btchip_apdu_sign_message_internal() { unsigned short btchip_apdu_sign_message() { unsigned short sw = btchip_apdu_sign_message_internal(); if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { - btchip_bagl_confirm_message_signature(); + ui_tx_confirm_message_signature(); } return sw; } diff --git a/src/ui/transaction/ui_transaction.h b/src/ui/transaction/ui_transaction.h index 1c22ff1..1c383ee 100644 --- a/src/ui/transaction/ui_transaction.h +++ b/src/ui/transaction/ui_transaction.h @@ -16,8 +16,8 @@ ********************************************************************************/ #pragma once -unsigned int btchip_bagl_confirm_full_output(void); -unsigned int btchip_bagl_confirm_single_output(void); -unsigned int btchip_bagl_finalize_tx(void); -void btchip_bagl_confirm_message_signature(void); -void btchip_bagl_request_change_path_approval(unsigned char* change_path); \ No newline at end of file +unsigned int ui_tx_confirm_full_output(void); +unsigned int ui_tx_confirm_single_output(void); +unsigned int ui_tx_finalize(void); +void ui_tx_confirm_message_signature(void); +void ui_tx_request_change_path_approval(unsigned char* change_path); \ No newline at end of file diff --git a/src/ui/transaction/ui_transaction_bagl.c b/src/ui/transaction/ui_transaction_bagl.c index 89f5434..3f962aa 100644 --- a/src/ui/transaction/ui_transaction_bagl.c +++ b/src/ui/transaction/ui_transaction_bagl.c @@ -557,7 +557,7 @@ UX_FLOW(ux_request_change_path_approval_flow, #endif // TARGET_NANOX || TARGET_NANOS2 -unsigned int btchip_bagl_confirm_full_output() { +unsigned int ui_tx_confirm_full_output() { if (!prepare_full_output(0)) { return 0; } @@ -572,7 +572,7 @@ unsigned int btchip_bagl_confirm_full_output() { return 1; } -unsigned int btchip_bagl_confirm_single_output() { +unsigned int ui_tx_confirm_single_output() { // TODO : remove when supporting multi output if (!prepare_single_output()) { return 0; @@ -592,7 +592,7 @@ unsigned int btchip_bagl_confirm_single_output() { return 1; } -unsigned int btchip_bagl_finalize_tx() { +unsigned int ui_tx_finalize() { if (!prepare_fees()) { return 0; } @@ -607,7 +607,7 @@ unsigned int btchip_bagl_finalize_tx() { return 1; } -void btchip_bagl_confirm_message_signature() { +void ui_tx_confirm_message_signature() { if (!prepare_message_signature()) { return; } @@ -621,7 +621,7 @@ void btchip_bagl_confirm_message_signature() { #endif // TARGET_NANOX } -void btchip_bagl_request_change_path_approval(unsigned char* change_path) +void ui_tx_request_change_path_approval(unsigned char* change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); #if defined(TARGET_NANOS) diff --git a/src/ui/transaction/ui_transaction_nbgl.c b/src/ui/transaction/ui_transaction_nbgl.c index cce3316..fbd890b 100644 --- a/src/ui/transaction/ui_transaction_nbgl.c +++ b/src/ui/transaction/ui_transaction_nbgl.c @@ -166,7 +166,7 @@ static void reviewStart(void) { msgs.reviewCancel, displayTransaction, rejectUseCaseChoice); } -unsigned int btchip_bagl_confirm_full_output() { +unsigned int ui_tx_confirm_full_output() { txType = TX_TYPE_FULL_REVIEW; if (!prepare_full_output(0)) { return 0; @@ -175,7 +175,7 @@ unsigned int btchip_bagl_confirm_full_output() { return 1; } -unsigned int btchip_bagl_finalize_tx() { +unsigned int ui_tx_finalize() { txType = TX_TYPE_FINALIZE; if (!prepare_fees()) { return 0; @@ -184,7 +184,7 @@ unsigned int btchip_bagl_finalize_tx() { return 1; } -void btchip_bagl_confirm_message_signature() { +void ui_tx_confirm_message_signature() { txType = TX_TYPE_SIGN_MESSAGE; if (!prepare_message_signature()) { @@ -193,7 +193,7 @@ void btchip_bagl_confirm_message_signature() { reviewStart(); } -unsigned int btchip_bagl_confirm_single_output() { +unsigned int ui_tx_confirm_single_output() { txType = TX_TYPE_SINGLE_OUTPUT; if (!prepare_single_output()) { return 0; @@ -212,7 +212,7 @@ static void changePathWarningChoice(bool reject) { } } -void btchip_bagl_request_change_path_approval(unsigned char* change_path) +void ui_tx_request_change_path_approval(unsigned char* change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); explicit_bzero(genericText, sizeof(genericText)); From 54cebe95eb5722590eb339c857e1abd8e26833d4 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 5 Dec 2022 10:56:54 +0100 Subject: [PATCH 15/41] Add Stax glyphs. --- glyphs/decred_icon_64px.bmp | Bin 0 -> 12342 bytes src/ui/main/ui_main_menu_nbgl.c | 2 +- src/ui/transaction/ui_transaction_nbgl.c | 5 +++-- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 glyphs/decred_icon_64px.bmp diff --git a/glyphs/decred_icon_64px.bmp b/glyphs/decred_icon_64px.bmp new file mode 100644 index 0000000000000000000000000000000000000000..54ba4a25bfecfde553d75ba05911bb593b8cfe41 GIT binary patch literal 12342 zcmeH|u}%ar3`Ccjl7>&9q`Df>^Z%c7M1-?)v-V_?tg@iXNz2)u@w3+;@%eRm-+n%q z^z$t}AHUDj_L`#fN&3rkesW>kuIsZdur9DJur9DJKre9nkJ0l@!6=FYur1C-U}THI zjuJtj?sR%3=;}y4s$bLLe*b+{rxE8pl4S$}5~JKSXz5FDu==;oud}XKofbKjDdveF zP&YphpsOS0d{9L`bVaF1Besa_)(NMS++Md>c2#4SAQr1|Gl;-svlbHQG~y(DkO%}M zXmnF(=}TR5RMbaA1gq;P;xt-QK!7H3pxH(OK7y-!?no~uo61Lss?i`I?cnT73BOfx z7a$PVuNMiqTiQ>LP<9#StiA;8i$EhhVvlI>F#AvVwa05;jD zw$fg*ig`{6Y>g9x)_o z{=zVktY=Q*`4_Li_dop=$a>;M1& literal 0 HcmV?d00001 diff --git a/src/ui/main/ui_main_menu_nbgl.c b/src/ui/main/ui_main_menu_nbgl.c index df12bcc..f8fca02 100644 --- a/src/ui/main/ui_main_menu_nbgl.c +++ b/src/ui/main/ui_main_menu_nbgl.c @@ -90,6 +90,6 @@ static void displaySettingsMenu(void) { void ui_idle(void) { setting_switch.initState = (bool) ! N_btchip.pubKeyRequestRestriction; - nbgl_useCaseHome("Decred", NULL/*&C_icon_stellar_64px*/, "This app confirms actions on\nthe Decred network.", true, displaySettingsMenu, onQuitCallback); + nbgl_useCaseHome("Decred",&C_decred_icon_64px, "This app confirms actions on\nthe Decred network.", true, displaySettingsMenu, onQuitCallback); } #endif // HAVE_NBGL diff --git a/src/ui/transaction/ui_transaction_nbgl.c b/src/ui/transaction/ui_transaction_nbgl.c index fbd890b..93badaf 100644 --- a/src/ui/transaction/ui_transaction_nbgl.c +++ b/src/ui/transaction/ui_transaction_nbgl.c @@ -27,6 +27,7 @@ #include "ui_transaction.h" #include "ui_shared.h" #include "btchip_internal.h" +#include "glyphs.h" typedef enum { TX_TYPE_SINGLE_OUTPUT = 0, @@ -113,7 +114,7 @@ static void reviewStart(void) { infoLongPress.text = "Accept and send"; infoLongPress.longPressText = "Hold to accept"; - infoLongPress.icon = NULL;//&C_decred_icon_64px; + infoLongPress.icon = &C_decred_icon_64px; pairs[0].item = "Amount"; pairs[0].value = vars.tmp.fullAmount; @@ -162,7 +163,7 @@ static void reviewStart(void) { } reviewStarted = false; - nbgl_useCaseReviewStart(NULL/*&C_decred_icon_64px*/, msgs.reviewStart, NULL, + nbgl_useCaseReviewStart(&C_decred_icon_64px, msgs.reviewStart, NULL, msgs.reviewCancel, displayTransaction, rejectUseCaseChoice); } From 51d9e25a811bbb94510d7666b4b64ddad4ace4fb Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 5 Dec 2022 10:58:03 +0100 Subject: [PATCH 16/41] Fix bug : Wrong structure type for message hash. --- include/btchip_context.h | 6 ++++++ src/btchip_apdu_sign_message.c | 26 +++++++++++++------------- src/ui/ui_shared.c | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/include/btchip_context.h b/include/btchip_context.h index 152964e..d9657d2 100644 --- a/include/btchip_context.h +++ b/include/btchip_context.h @@ -20,6 +20,7 @@ #define BTCHIP_CONTEXT_H #include "os.h" +#include "cx.h" #include "btchip_secure_value.h" #include "btchip_filesystem_tx.h" #include "blake256.h" @@ -159,6 +160,11 @@ struct btchip_context_s { unsigned char last_token[4]; unsigned char has_valid_token; + /** Sign message prefix hash context */ + cx_sha256_t messageHashPrefix; + /** Sign message witness hash context */ + cx_sha256_t messageHashWitness; + /** Transaction Prefix hash context */ BLAKE256_CTX transactionHashPrefix; /** Transaction Witness hash context */ diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 86296aa..a164244 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -121,17 +121,17 @@ unsigned short btchip_apdu_sign_message_internal() { goto discard; } btchip_context_D.hashedMessageLength = 0; - cx_sha256_init(&btchip_context_D.transactionHashPrefix); + cx_sha256_init(&btchip_context_D.messageHashPrefix); cx_sha256_init( - &btchip_context_D.transactionHashWitness); + &btchip_context_D.messageHashWitness); chunkLength = btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH; - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + cx_hash(&btchip_context_D.messageHashPrefix.header, 0, &chunkLength, 1, NULL, 0); - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + cx_hash(&btchip_context_D.messageHashPrefix.header, 0, btchip_context_D.coinId, btchip_context_D.coinIdLength, NULL, 0); - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + cx_hash(&btchip_context_D.messageHashPrefix.header, 0, (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0); if (btchip_context_D.transactionSummary.messageLength < 0xfd) { @@ -149,7 +149,7 @@ unsigned short btchip_apdu_sign_message_internal() { 0xff); messageLengthSize = 3; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + cx_hash(&btchip_context_D.messageHashPrefix.header, 0, messageLength, messageLengthSize, NULL, 0); chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); if ((btchip_context_D.hashedMessageLength + chunkLength) > @@ -159,10 +159,10 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + cx_hash(&btchip_context_D.messageHashPrefix.header, 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0); cx_hash( - &btchip_context_D.transactionHashWitness.header, + &btchip_context_D.messageHashWitness.header, 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0); btchip_context_D.hashedMessageLength += chunkLength; G_io_apdu_buffer[0] = 0x00; @@ -181,10 +181,10 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashPrefix.header, 0, + cx_hash(&btchip_context_D.messageHashPrefix.header, 0, G_io_apdu_buffer + offset, apduLength, NULL, 0); cx_hash( - &btchip_context_D.transactionHashWitness.header, + &btchip_context_D.messageHashWitness.header, 0, G_io_apdu_buffer + offset, apduLength, NULL, 0); btchip_context_D.hashedMessageLength += apduLength; G_io_apdu_buffer[0] = 0x00; @@ -243,10 +243,10 @@ unsigned short btchip_compute_hash() { btchip_context_D.outLength = 0; BEGIN_TRY { TRY { - cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, + cx_hash(&btchip_context_D.messageHashPrefix.header, CX_LAST, hash, 0, hash, 32); - cx_sha256_init(&btchip_context_D.transactionHashPrefix); - cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, hash, + cx_sha256_init(&btchip_context_D.messageHashPrefix); + cx_hash(&btchip_context_D.messageHashPrefix.header, CX_LAST, hash, 32, hash, 32); btchip_private_derive_keypair( btchip_context_D.transactionSummary.summarydata.keyPath, 0, diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 4e82f6c..8b9771f 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -155,7 +155,7 @@ uint8_t prepare_fees() { uint8_t prepare_message_signature() { uint8_t buffer[32]; - cx_hash((cx_hash_t *)&btchip_context_D.transactionHashWitness.header, CX_LAST, + cx_hash((cx_hash_t *)&btchip_context_D.messageHashWitness.header, CX_LAST, (const unsigned char *) vars.tmp.fullAmount, 0, buffer, 32); #ifdef HAVE_NBGL From 276eb5acc10ab3b98c730d23f36baa9ed06adaf7 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 5 Dec 2022 11:02:16 +0100 Subject: [PATCH 17/41] Clean up : - Remove obsolete PRINTF calls. - Remove definition of obsolete Blue UX function. - Comment macro redefinition. - Cast variable to proper type. --- src/btchip_apdu_get_trusted_input.c | 2 +- src/btchip_apdu_hash_sign.c | 1 - src/btchip_context.c | 1 - src/btchip_transaction.c | 2 +- src/main.c | 6 ------ 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/btchip_apdu_get_trusted_input.c b/src/btchip_apdu_get_trusted_input.c index b985adf..e24af22 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/btchip_apdu_get_trusted_input.c @@ -82,7 +82,7 @@ unsigned short btchip_apdu_get_trusted_input() { memmove(G_io_apdu_buffer + 4 + 32 + 4, btchip_context_D.transactionContext.transactionAmount, 8); - cx_hmac_sha256(N_btchip.bkp.trustedinput_key, + cx_hmac_sha256((const uint8_t*) N_btchip.bkp.trustedinput_key, sizeof(N_btchip.bkp.trustedinput_key), G_io_apdu_buffer, TRUSTEDINPUT_SIZE, trustedInputSignature, 32); memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 087a9f2..2824a22 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -131,7 +131,6 @@ unsigned short btchip_apdu_hash_sign() { // Sign - PRINTF("Pub key: %.*H\n", sizeof(public_key_D.W), public_key_D.W); btchip_signverify_finalhash( &btchip_private_key_D, 1, hash2, sizeof(hash2), G_io_apdu_buffer, sizeof(G_io_apdu_buffer), diff --git a/src/btchip_context.c b/src/btchip_context.c index 39a9427..2c73821 100644 --- a/src/btchip_context.c +++ b/src/btchip_context.c @@ -38,7 +38,6 @@ void autosetup(void){ */ void btchip_context_init() { PRINTF("Context init\n"); - PRINTF(N_btchip.bkp); explicit_bzero(&btchip_context_D, sizeof(btchip_context_D)); SB_SET(btchip_context_D.halted, 0); btchip_context_D.currentOutputOffset = 0; diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 134d2a4..09092b4 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -19,7 +19,7 @@ #include "btchip_apdu_constants.h" #include "blake256.h" -#define DEBUG_LONG "%ld" +// #define DEBUG_LONG "%ld" #define DEBUG_LONG "%d" diff --git a/src/main.c b/src/main.c index dc874cd..3a43fe3 100644 --- a/src/main.c +++ b/src/main.c @@ -67,12 +67,6 @@ ux_state_t ux; #endif // TARGET_NANOX || TARGET_NANOS2 #ifndef TARGET_FATSTACKS -const bagl_element_t *ui_menu_item_out_over(const bagl_element_t *e) { - // the selection rectangle is after the none|touchable - e = (const bagl_element_t *)(((unsigned int)e) + sizeof(bagl_element_t)); - return e; -} - // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { From 58338b13ac679fa49a422561bb25a48143bd781a Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 5 Dec 2022 16:37:18 +0100 Subject: [PATCH 18/41] Automate tests with Ragger. --- test/1to2.py | 180 ------------------ test/1to2_warning_change.py | 180 ------------------ test/2to2.py | 316 ------------------------------ test/conftest.py | 105 ++++++++++ test/test_1to2.py | 176 +++++++++++++++++ test/test_1to2_warning_change.py | 223 ++++++++++++++++++++++ test/test_2to2.py | 317 +++++++++++++++++++++++++++++++ test/test_sign_message.py | 54 ++++++ 8 files changed, 875 insertions(+), 676 deletions(-) delete mode 100755 test/1to2.py delete mode 100755 test/1to2_warning_change.py delete mode 100755 test/2to2.py create mode 100755 test/conftest.py create mode 100755 test/test_1to2.py create mode 100755 test/test_1to2_warning_change.py create mode 100755 test/test_2to2.py create mode 100755 test/test_sign_message.py diff --git a/test/1to2.py b/test/1to2.py deleted file mode 100755 index d5ecae3..0000000 --- a/test/1to2.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python -#******************************************************************************* -#* Ledger App -#* (c) 2016-2019 Ledger -#* -#* 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. -#******************************************************************************** - - -from ledgerblue.comm import getDongle -from ledgerblue.commException import CommException -from binascii import hexlify -from time import sleep - - -dongle = getDongle(True) - - - - -################# GET PUBKEY ######################### (only for testing sake) - -packets = [ -"058000002c8000002a800000000000000000000001" # BIP32 path len, BIP32 path -] - - -packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -# 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key -# 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 -# c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode - - - - -################# GET TRUSTED INPUT ######################### - - -packets = [ -"000000010100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs -"60fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) -"4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff", #witness + sequence -"02", # outputs -"069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac", #amount + script version + script -"405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac", #amount + script version + script -"0000000000000000" #locktime + expiry -] - -packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -trusted_input = result - - -# [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] -#<= 32 00 7f62 334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804 01000000 4054890000000000 cc76201c83268593 9000 - -expected = "334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result[4:-8]).decode("utf-8"), expected)) - exit() - - -################# HASH INPUT START ######################### - -packets = [ -"0100000001",#version + number of input -#"0138320006a640c65057afdd582f4f086c6e6e8c160092e4c0d32b9faa9fa91b8feb1048379c020000002ac503f20100000085bdec7eae8ace3a01", -"01" + "%0.2X" % len(trusted_input) + hexlify(trusted_input).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len -"76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff" # spend output script + sequence -] - - - -packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0448000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -################# HASH INPUT FINALIZE WITH CHANGE ######################### - -packets = [ -"058000002c8000002A800000000000000100000001", # change address bip44 path -"02ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac" #num output + amount + script version + new lock script + same for change addr -] - - -packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:-1]: - - packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] -result = dongle.exchange(bytearray.fromhex(packet)) - - - -################# HASH SIGN ######################### - -packets = [ -"058000002c8000002A800000000000000000000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type -] - - -packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -# 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce 01 witness signature + sighash flag - -expected = "31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result).decode("utf-8"), expected)) - exit() - - - - -''' -APDU EXCHANGE RECAP: - -HID => e042000009000000010100000001 -HID <= 9000 -HID => e04280002660fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b -HID <= 9000 -HID => e04280006f4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff -HID <= 9000 -HID => e04280000102 -HID <= 9000 -HID => e042800024069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac -HID <= 9000 -HID => e042800024405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac -HID <= 9000 -HID => e0428000080000000000000000 -HID <= 32007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685939000 -HID => e0440000050100000001 -HID <= 9000 -HID => e04480003c013832007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685930019 -HID <= 9000 -HID => e04480001d76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff -HID <= 9000 -HID => e04aff0015058000002c8000002a800000000000000100000001 -HID <= 9000 -HID => e04a80004902ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac -HID <= 00009000 -HID => e04800001e058000002c8000002a800000000000000000000001000000000000000001 -HID <= 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce019000 - -''' diff --git a/test/1to2_warning_change.py b/test/1to2_warning_change.py deleted file mode 100755 index 7010532..0000000 --- a/test/1to2_warning_change.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python -#******************************************************************************* -#* Ledger App -#* (c) 2016-2019 Ledger -#* -#* 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. -#******************************************************************************** - - -from ledgerblue.comm import getDongle -from ledgerblue.commException import CommException -from binascii import hexlify -from time import sleep - - -dongle = getDongle(True) - - - - -################# GET PUBKEY ######################### (only for testing sake) - -packets = [ -"058000002c8000002a800000000000000000000001" # BIP32 path len, BIP32 path -] - - -packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -# 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key -# 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 -# c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode - - - - -################# GET TRUSTED INPUT ######################### - - -packets = [ -"000000010100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs -"60fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) -"4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff", #witness + sequence -"02", # outputs -"069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac", #amount + script version + script -"405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac", #amount + script version + script -"0000000000000000" #locktime + expiry -] - -packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -trusted_input = result - - -# [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] -#<= 32 00 7f62 334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804 01000000 4054890000000000 cc76201c83268593 9000 - -expected = "334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result[4:-8]).decode("utf-8"), expected)) - exit() - - -################# HASH INPUT START ######################### - -packets = [ -"0100000001",#version + number of input -#"0138320006a640c65057afdd582f4f086c6e6e8c160092e4c0d32b9faa9fa91b8feb1048379c020000002ac503f20100000085bdec7eae8ace3a01", -"01" + "%0.2X" % len(trusted_input) + hexlify(trusted_input).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len -"76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff" # spend output script + sequence -] - - - -packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0448000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -################# HASH INPUT FINALIZE WITH CHANGE ######################### - -packets = [ -"058000002c8000002A800000000000000110000001", # change address bip44 path (very high index) (should update next line to be valid, this is just to display the warning) -"02ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac" #num output + amount + script version + new lock script + same for change addr -] - - -packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:-1]: - - packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] -result = dongle.exchange(bytearray.fromhex(packet)) - - - -################# HASH SIGN ######################### - -packets = [ -"058000002c8000002A800000000000000000000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type -] - - -packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -# 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce 01 witness signature + sighash flag - -expected = "31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result).decode("utf-8"), expected)) - exit() - - - - -''' -APDU EXCHANGE RECAP: - -HID => e042000009000000010100000001 -HID <= 9000 -HID => e04280002660fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b -HID <= 9000 -HID => e04280006f4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff -HID <= 9000 -HID => e04280000102 -HID <= 9000 -HID => e042800024069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac -HID <= 9000 -HID => e042800024405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac -HID <= 9000 -HID => e0428000080000000000000000 -HID <= 32007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685939000 -HID => e0440000050100000001 -HID <= 9000 -HID => e04480003c013832007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685930019 -HID <= 9000 -HID => e04480001d76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff -HID <= 9000 -HID => e04aff0015058000002c8000002a800000000000000100000001 -HID <= 9000 -HID => e04a80004902ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac -HID <= 00009000 -HID => e04800001e058000002c8000002a800000000000000000000001000000000000000001 -HID <= 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce019000 - -''' diff --git a/test/2to2.py b/test/2to2.py deleted file mode 100755 index 7969e0e..0000000 --- a/test/2to2.py +++ /dev/null @@ -1,316 +0,0 @@ -#!/usr/bin/env python -#******************************************************************************* -#* Ledger App -#* (c) 2016-2019 Ledger -#* -#* 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. -#******************************************************************************** - - -from ledgerblue.comm import getDongle -from ledgerblue.commException import CommException -from binascii import hexlify -from time import sleep - - -dongle = getDongle(True) - - -''' - -################# GET PUBKEY ######################### - -packets = [ -"058000002c80000001800000000000000000000001" # BIP32 path len, BIP32 path -] - - -packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -# 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key -# 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 -# c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode - -''' - -################# GET TRUSTED INPUT 1 ######################### - - -packets = [ -"000000000100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs -"334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000000000", #wrong endian txid + outpout index + tree + witness size (0 for decred) -"ffffffff", #witness (0 in decred) + sequence -"02", # outputs -"ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac", #amount + script version + script -"c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac", #amount + script version + script -"0000000000000000" #locktime + expiry -] - -packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -trusted_input_1 = result - -# [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] -#<= 32 00 16c5 9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d 00000000 ac211e0000000000 598355bee9a1e576 9000 - -expected = "9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result[4:-8]).decode("utf-8"), expected)) - exit() - - -################# GET TRUSTED INPUT 2 ######################### - - -packets = [ -"000000010100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs -"334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000000000", #wrong endian txid + outpout index + tree + witness size (0 for decred) -"ffffffff", #witness (0 in decred) + sequence -"02", # outputs -"ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac", #amount + script version + script -"c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac", #amount + script version + script -"0000000000000000" #locktime + expiry -] - -packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -trusted_input_2 = result - -# [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] -#<= 32 00 dcac 9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d 01000000 c0cf6a0000000000 f0d368a53f42bdcd 9000 - - -expected = "9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result[4:-8]).decode("utf-8"), expected)) - exit() - - -################# HASH INPUT START ######################### - -packets = [ -"0100000002",#version + number of input -"01" + "%0.2X" % len(trusted_input_1) + hexlify(trusted_input_1).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len -"76a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acffffffff", # spend output script + sequence -"01" + "%0.2X" % len(trusted_input_2) + hexlify(trusted_input_2).decode("utf-8") + "00" + "00", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len -"ffffffff" # spend output script + sequence -] - - - -packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0448000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -################# HASH INPUT FINALIZE WITH CHANGE ######################### - -packets = [ -"058000002c8000002A800000000000000100000002", # change address bip44 path (size + path) -"02c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac" #num output + amount + script version + new lock script + same for change addr -] - - -packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:-1]: - - packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] -result = dongle.exchange(bytearray.fromhex(packet)) - - - -################# HASH SIGN N°1 ######################### - -packets = [ -"058000002c8000002A800000000000000100000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type -] - - -packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -# 3045022100ce8f37f615e60bd604b5c2e78a64068e0fc00a2fd06932060f27bc1e804ba90b02204f72ae4161f8935504d04242a5841b45e8f2776c22655aa3ac7f430f196af038 01 witness signature + sighash flag - -expected = "3045022100ce8f37f615e60bd604b5c2e78a64068e0fc00a2fd06932060f27bc1e804ba90b02204f72ae4161f8935504d04242a5841b45e8f2776c22655aa3ac7f430f196af03801" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result).decode("utf-8"), expected)) - exit() - - -################# ######################### -################# WITNESS N°2 ######################### -################# ######################### - - - - -################# HASH INPUT START N°2 ######################### - -packets = [ -"0100000002",#version + number of input -"01" + "%0.2X" % len(trusted_input_1) + hexlify(trusted_input_1).decode("utf-8") + "00" + "00", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len -"ffffffff", # spend output script + sequence -"01" + "%0.2X" % len(trusted_input_2) + hexlify(trusted_input_2).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len -"76a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888acffffffff" # spend output script + sequence -] - - - -packets[0] = "e0440080" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0448080" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -################# HASH INPUT FINALIZE WITH CHANGE N°2 ######################### - -packets = [ -#"058000002c8000002A800000000000000100000002", # change address bip44 path (size + path) -"02c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac" #num output + amount + script version + new lock script + same for change addr -] - -# unused in this case, but useful when packet is splitted in smaller ones -for packet in packets[1:-1]: - - packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - - -packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] -result = dongle.exchange(bytearray.fromhex(packet)) - - - -################# HASH SIGN N°2 ######################### - -packets = [ -"058000002c8000002A800000000000000000000002000000000000000001" #signing key path len + path + lock time + expiry + sighash type -] - - -packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] -result = dongle.exchange(bytearray.fromhex(packets[0])) - -for packet in packets[1:]: - - packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - -# 3144022041b371311dc2f2dc72b83e8249d3fc0f53f6bfc9ccdb214eeea7b35914ba187602200de4313f2dca0aa2ca857afb65e06d693128e6e4b9b127eff018ddcfe98c462e 01 witness signature + sighash flag - -expected = "3144022041b371311dc2f2dc72b83e8249d3fc0f53f6bfc9ccdb214eeea7b35914ba187602200de4313f2dca0aa2ca857afb65e06d693128e6e4b9b127eff018ddcfe98c462e01" - -if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result).decode("utf-8"), expected)) - exit() - - - - - -''' -APDU EXCHANGE RECAP: - -HID => e042000009000000000100000001 -HID <= 9000 -HID => e042800026334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b180401000000006b -HID <= 9000 -HID => e04280006f4830450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01210306c8988cab4694d1969c77ee5253e6ed5de7368f3f7713e3d5c512b8fd312562ffffffff -HID <= 9000 -HID => e04280000102 -HID <= 9000 -HID => e042800024ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac -HID <= 9000 -HID => e042800024c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac -HID <= 9000 -HID => e0428000080000000000000000 -HID <= 320016c59e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000598355bee9a1e5769000 -HID => e042000009000000010100000001 -HID <= 9000 -HID => e042800026334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b180401000000006b -HID <= 9000 -HID => e04280006f4830450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01210306c8988cab4694d1969c77ee5253e6ed5de7368f3f7713e3d5c512b8fd312562ffffffff -HID <= 9000 -HID => e04280000102 -HID <= 9000 -HID => e042800024ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac -HID <= 9000 -HID => e042800024c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac -HID <= 9000 -HID => e0428000080000000000000000 -HID <= 3200dcac9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000f0d368a53f42bdcd9000 -HID => e0440000050100000002 -HID <= 9000 -HID => e04480003c0138320016c59e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000598355bee9a1e5760019 -HID <= 9000 -HID => e04480001d76a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acffffffff -HID <= 9000 -HID => e04480003c01383200dcac9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000f0d368a53f42bdcd0000 -HID <= 9000 -HID => e044800004ffffffff -HID <= 9000 -HID => e04aff0015058000002c8000002a800000000000000100000002 -HID <= 9000 -HID => e04a80004902c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac -HID <= 00009000 -HID => e04800001e058000002c8000002a800000000000000100000001000000000000000001 -HID <= 3045022100ce8f37f615e60bd604b5c2e78a64068e0fc00a2fd06932060f27bc1e804ba90b02204f72ae4161f8935504d04242a5841b45e8f2776c22655aa3ac7f430f196af038019000 -HID => e0440080050100000002 -HID <= 9000 -HID => e04480803c0138320016c59e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000598355bee9a1e5760000 -HID <= 9000 -HID => e044808004ffffffff -HID <= 9000 -HID => e04480803c01383200dcac9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000f0d368a53f42bdcd0019 -HID <= 9000 -HID => e04480801d76a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888acffffffff -HID <= 9000 -HID => e04a80004902c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac -HID <= 00009000 -HID => e04800001e058000002c8000002a800000000000000000000002000000000000000001 -HID <= 3144022041b371311dc2f2dc72b83e8249d3fc0f53f6bfc9ccdb214eeea7b35914ba187602200de4313f2dca0aa2ca857afb65e06d693128e6e4b9b127eff018ddcfe98c462e019000 -''' \ No newline at end of file diff --git a/test/conftest.py b/test/conftest.py new file mode 100755 index 0000000..375d3e5 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,105 @@ +import os +# from turtle import back +import pytest +from pathlib import Path + +# from venvtron.lib.python3.8.site-packages.mnemonic.mnemonic import Mnemonic +from ragger import Firmware +from ragger.navigator import NanoNavigator, FatstacksNavigator +from ragger.backend import SpeculosBackend, LedgerCommBackend +from time import sleep + +SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) + +# This variable is needed for Speculos only (physical tests need the application to be already installed) +APPS_DIRECTORY = (Path(__file__).parent / "elfs").resolve() +APP_PREFIX = "decred" + +# This variable will be useful in tests to implement different behavior depending on the firmware +FIRMWARES = [Firmware('nanos', '2.1'), + Firmware('nanosp', '1.0.3'), + Firmware('nanox', '2.0.2'), + Firmware('fat', '1.0')] + +BACKENDS = ["speculos", "ledgercomm", "ledgerwallet"] + +MNEMONIC = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" + +# Glue to call every test that depends on the firmware once for each required firmware +def pytest_generate_tests(metafunc): + if "firmware" in metafunc.fixturenames: + fw_list = [] + ids = [] + # First pass: enable only demanded firmwares + for fw in FIRMWARES: + if metafunc.config.getoption(fw.device): + fw_list.append(fw) + ids.append(fw.device + " " + fw.version) + # Second pass if no specific firmware demanded: add them all + if not fw_list: + for fw in FIRMWARES: + fw_list.append(fw) + ids.append(fw.device + " " + fw.version) + metafunc.parametrize("firmware", fw_list, ids=ids, scope="session") + +# adding a pytest CLI option "--backend" +def pytest_addoption(parser): + parser.addoption("--backend", action="store", default="speculos") + parser.addoption("--golden_run", action="store_true", default=False) + # Enable ussing --'device' in the pytest command line to restrict testing to specific devices + for fw in FIRMWARES: + parser.addoption("--"+fw.device, action="store_true", help="run on specified device only") + +# accessing the value of the "--backend" option as a fixture +@pytest.fixture(scope="session") +def backend(pytestconfig): + return pytestconfig.getoption("backend") + +def app_path_from_app_name(app_dir, app_name: str, device: str) -> Path: + assert app_dir.is_dir(), f"{app_dir} is not a directory" + app_path = app_dir / (app_name + "_" + device + ".elf") + assert app_path.is_file(), f"{app_path} must exist" + return app_path + +def prepare_speculos_args(firmware): + speculos_args = ["--model", firmware.device, "--sdk", firmware.version, "--seed", MNEMONIC] + # Uncomment line below to enable display + speculos_args += ["--display", "qt"] + app_path = app_path_from_app_name(APPS_DIRECTORY, APP_PREFIX, firmware.device) + return ([app_path], {"args": speculos_args}) + +# Depending on the "--backend" option value, a different backend is +# instantiated, and the tests will either run on Speculos or on a physical +# device depending on the backend +def create_backend(backend: str, firmware: Firmware): + # if backend.lower() == "ledgercomm": + # return LedgerCommBackend(firmware, interface="hid") + # elif backend.lower() == "ledgerwallet": + # return LedgerWalletBackend(firmware) + if backend.lower() == "speculos": + args, kwargs = prepare_speculos_args(firmware) + return SpeculosBackend(*args, firmware, **kwargs) + else: + raise ValueError(f"Backend '{backend}' is unknown. Valid backends are: {BACKENDS}") + + +@pytest.fixture(scope="session") +def golden_run(pytestconfig): + return pytestconfig.getoption("golden_run") + +@pytest.fixture(scope="session") +def navigator(client, firmware, golden_run): + if firmware.device.startswith("fat"): + return FatstacksNavigator(client, firmware, golden_run) + elif firmware.device.startswith("nano"): + return NanoNavigator(client, firmware, golden_run) + else: + raise ValueError(f"Device '{firmware.device}' is unsupported.") + + +# This final fixture will return the properly configured backend client, to be used in tests +@pytest.fixture(scope="session") +def client(backend, firmware): + with create_backend(backend, firmware) as b: + yield b + diff --git a/test/test_1to2.py b/test/test_1to2.py new file mode 100755 index 0000000..1417b2c --- /dev/null +++ b/test/test_1to2.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +#******************************************************************************* +#* Ledger App +#* (c) 2016-2019 Ledger +#* +#* 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. +#******************************************************************************** +from ragger.navigator import NavInsID, NavIns +from binascii import hexlify + +trusted_input = None + +################ GET PUBKEY ######################### (only for testing sake) +def test_decred_get_pubkey(client, firmware, navigator): + packets = [ + "058000002c8000002a800000000000000000000001" # BIP32 path len, BIP32 path + ] + + packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + + # 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key + # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 + # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + + with client.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "fat": + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.USE_CASE_CHOICE_CONFIRM)]) + if firmware.device in ["nanox","nanosp"]: + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + if firmware.device == "nanos": + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + +# ################# GET TRUSTED INPUT ######################### +def test_decred_get_trusted_input(client, firmware, navigator): + packets = [ + "000000010100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs + "60fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) + "4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff", #witness + sequence + "02", # outputs + "069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac", #amount + script version + script + "405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac", #amount + script version + script + "0000000000000000" #locktime + expiry + ] + + packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + for packet in packets[1:]: + packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + global trusted_input + trusted_input = result + + # [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] + #<= 32 00 7f62 334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804 01000000 4054890000000000 cc76201c83268593 9000 + + expected = "334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000" + + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result.data[4:-8]).decode("utf-8"), expected)) + exit() + + print("Success:\nExpected:%s\nGot: %s\n" % (hexlify(result.data[4:-8]).decode("utf-8"), expected)) + + +# ################# HASH INPUT START ######################### +def test_decred_hash_input_start(client, firmware, navigator): + packets = [ + "0100000001",#version + number of input + #"0138320006a640c65057afdd582f4f086c6e6e8c160092e4c0d32b9faa9fa91b8feb1048379c020000002ac503f20100000085bdec7eae8ace3a01", + "01" + "%0.2X" % len(trusted_input.data) + hexlify(trusted_input.data).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len + "76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff" # spend output script + sequence + ] + + packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + packet = "e0448000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + +# ################# HASH INPUT FINALIZE WITH CHANGE ######################### +def test_decred_hash_input_finalize(client, firmware, navigator): + packets = [ + "058000002c8000002A800000000000000100000001", # change address bip44 path + "02ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac" #num output + amount + script version + new lock script + same for change addr + ] + + packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:-1]: + + packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] + + with client.exchange_async_raw(data=bytearray.fromhex(packet)) as r: + if firmware.device == "fat": + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.USE_CASE_REVIEW_CONFIRM)]) + if firmware.device in ["nanox","nanosp"]: + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + if firmware.device == "nanos": + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + +# ################# HASH SIGN ######################### +def test_decred_sign(client, firmware, navigator): + packets = [ + "058000002c8000002A800000000000000000000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type + ] + + packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + expected = "31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01" + + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result.data).decode("utf-8"), expected)) + exit() + + +''' +APDU EXCHANGE RECAP: + +HID => e042000009000000010100000001 +HID <= 9000 +HID => e04280002660fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b +HID <= 9000 +HID => e04280006f4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff +HID <= 9000 +HID => e04280000102 +HID <= 9000 +HID => e042800024069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac +HID <= 9000 +HID => e042800024405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac +HID <= 9000 +HID => e0428000080000000000000000 +HID <= 32007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685939000 +HID => e0440000050100000001 +HID <= 9000 +HID => e04480003c013832007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685930019 +HID <= 9000 +HID => e04480001d76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff +HID <= 9000 +HID => e04aff0015058000002c8000002a800000000000000100000001 +HID <= 9000 +HID => e04a80004902ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac +HID <= 00009000 +HID => e04800001e058000002c8000002a800000000000000000000001000000000000000001 +HID <= 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce019000 + +''' diff --git a/test/test_1to2_warning_change.py b/test/test_1to2_warning_change.py new file mode 100755 index 0000000..73aa3a6 --- /dev/null +++ b/test/test_1to2_warning_change.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +#******************************************************************************* +#* Ledger App +#* (c) 2016-2019 Ledger +#* +#* 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. +#******************************************************************************** +# import sys +# import struct +# from contextlib import contextmanager +# from pathlib import Path +from ragger.backend import RaisePolicy +from ragger.error import ExceptionRAPDU +from ragger import Crop, RAPDU +from ragger.navigator import NavInsID, NavIns +from time import sleep + +from ledgerblue.comm import getDongle +from ledgerblue.commException import CommException +from binascii import hexlify +from time import sleep + +trusted_input = None + +################# GET PUBKEY ######################### (only for testing sake) +def test_decred_get_pubkey(client, firmware, navigator): + client.raise_policy = RaisePolicy.RAISE_NOTHING + packets = [ + "058000002c8000002a800000000000000000000001" # BIP32 path len, BIP32 path + ] + + packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + with client.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "fat": + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.USE_CASE_CHOICE_CONFIRM)]) + if firmware.device in ["nanox","nanosp"]: + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + if firmware.device == "nanos": + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + + # 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key + # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 + # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + +################# GET TRUSTED INPUT ######################### +def test_decred_get_trusted_input(client, firmware, navigator): + client.raise_policy = RaisePolicy.RAISE_NOTHING + packets = [ + "000000010100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs + "60fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) + "4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff", #witness + sequence + "02", # outputs + "069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac", #amount + script version + script + "405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac", #amount + script version + script + "0000000000000000" #locktime + expiry + ] + + packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + global trusted_input + trusted_input = result + + + # [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] + #<= 32 00 7f62 334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804 01000000 4054890000000000 cc76201c83268593 9000 + + expected = "334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000" + + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result.data[4:-8]).decode("utf-8"), expected)) + exit() + + +################# HASH INPUT START ######################### +def test_decred_hash_input_start(client, firmware, navigator): + client.raise_policy = RaisePolicy.RAISE_NOTHING + packets = [ + "0100000001",#version + number of input + #"0138320006a640c65057afdd582f4f086c6e6e8c160092e4c0d32b9faa9fa91b8feb1048379c020000002ac503f20100000085bdec7eae8ace3a01", + "01" + "%0.2X" % len(trusted_input.data) + hexlify(trusted_input.data).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len + "76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff" # spend output script + sequence + ] + + packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + packet = "e0448000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + +################# HASH INPUT FINALIZE WITH CHANGE ######################### +def test_decred_finalize(client, firmware, navigator): + client.raise_policy = RaisePolicy.RAISE_NOTHING + packets = [ + "058000002c8000002A800000000000000110000001", # change address bip44 path (very high index) (should update next line to be valid, this is just to display the warning) + "02ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac" #num output + amount + script version + new lock script + same for change addr + ] + + + packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + with client.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "fat": + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.USE_CASE_CHOICE_REJECT)]) + if firmware.device in ["nanox","nanosp"]: + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + if firmware.device == "nanos": + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + + for packet in packets[1:-1]: + packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + assert (result.status == 0x9000) + + packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] + + with client.exchange_async_raw(data=bytearray.fromhex(packet)) as r: + if firmware.device == "fat": + for _ in range(3): + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.USE_CASE_REVIEW_CONFIRM)]) + if firmware.device in ["nanox","nanosp"]: + for _ in range(2): + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + if firmware.device == "nanos": + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + + + +################# HASH SIGN ######################### +def test_decred_sign(client, firmware, navigator): + client.raise_policy = RaisePolicy.RAISE_NOTHING + packets = [ + "058000002c8000002A800000000000000000000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type + ] + + packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + sleep(5) + assert (result.status == 0x9000) + + for packet in packets[1:]: + + packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + sleep(5) + assert (result.status == 0x9000) + + # 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce 01 witness signature + sighash flag + expected = "31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01" + + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result.data).decode("utf-8"), expected)) + exit() + + +''' +APDU EXCHANGE RECAP: + +HID => e042000009000000010100000001 +HID <= 9000 +HID => e04280002660fe7d21bfbd946b5bc96e7819b531d42961300ecf451d428d6ea866f02e98e901000000006b +HID <= 9000 +HID => e04280006f4830450221009af49a50a71cfefb659ed4a61e8d5813622971a59187262c43a32c99a4e2daf00220344981e523f1e2bc19db62e3abaf346c7f1ae82d340438945183e1a23adb968c0121023bb5d9b33f895dddaadc173c1ccce15eb7800b0261775081e2d026f35d9249a5ffffffff +HID <= 9000 +HID => e04280000102 +HID <= 9000 +HID => e042800024069046800000000000001976a914beb827a5a42918e1def4fe9f635cc1aa3abdfd4f88ac +HID <= 9000 +HID => e042800024405489000000000000001976a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188ac +HID <= 9000 +HID => e0428000080000000000000000 +HID <= 32007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685939000 +HID => e0440000050100000001 +HID <= 9000 +HID => e04480003c013832007f62334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000cc76201c832685930019 +HID <= 9000 +HID => e04480001d76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff +HID <= 9000 +HID => e04aff0015058000002c8000002a800000000000000100000001 +HID <= 9000 +HID => e04a80004902ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac +HID <= 00009000 +HID => e04800001e058000002c8000002a800000000000000000000001000000000000000001 +HID <= 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce019000 + +''' diff --git a/test/test_2to2.py b/test/test_2to2.py new file mode 100755 index 0000000..a70a5cf --- /dev/null +++ b/test/test_2to2.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python +#******************************************************************************* +#* Ledger App +#* (c) 2016-2019 Ledger +#* +#* 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. +#******************************************************************************** +from binascii import hexlify +from ragger.navigator import NavInsID, NavIns + +trusted_input_1 = None +trusted_input_2 = None + +''' + +################# GET PUBKEY ######################### + +packets = [ +"058000002c80000001800000000000000000000001" # BIP32 path len, BIP32 path +] + + +packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] +result = dongle.exchange(bytearray.fromhex(packets[0])) + +# 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key +# 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 +# c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + +''' + +################# GET TRUSTED INPUT 1 ######################### +def test_decred_get_trusted_input_1(client, firmware, navigator): + packets = [ + "000000000100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs + "334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000000000", #wrong endian txid + outpout index + tree + witness size (0 for decred) + "ffffffff", #witness (0 in decred) + sequence + "02", # outputs + "ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac", #amount + script version + script + "c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac", #amount + script version + script + "0000000000000000" #locktime + expiry + ] + + packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + + packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + # result = dongle.exchange(bytearray.fromhex(packet)) + result = client.exchange_raw(data=bytearray.fromhex(packet)) + global trusted_input_1 + trusted_input_1 = result + + # [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] + #<= 32 00 16c5 9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d 00000000 ac211e0000000000 598355bee9a1e576 9000 + + expected = "9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000" + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % (expected,hexlify(result.data[4:-8]).decode("utf-8"))) + exit() + + +################# GET TRUSTED INPUT 2 ######################### +def test_decred_get_trusted_input_2(client, firmware, navigator): + packets = [ + "000000010100000001", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs + "334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000000000", #wrong endian txid + outpout index + tree + witness size (0 for decred) + "ffffffff", #witness (0 in decred) + sequence + "02", # outputs + "ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac", #amount + script version + script + "c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac", #amount + script version + script + "0000000000000000" #locktime + expiry + ] + + packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + + packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + global trusted_input_2 + trusted_input_2 = result + + # [magic + 00 + rand(2) + input txid (LE) + input index + amount + HMAC] + #<= 32 00 dcac 9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d 01000000 c0cf6a0000000000 f0d368a53f42bdcd 9000 + + expected = "9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000" + + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % (expected,hexlify(result.data[4:-8]).decode("utf-8") )) + exit() + + +################# HASH INPUT START ######################### +def test_decred_input_start_1(client, firmware, navigator): + packets = [ + "0100000002",#version + number of input + "01" + "%0.2X" % len(trusted_input_1.data) + hexlify(trusted_input_1.data).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len + "76a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acffffffff", # spend output script + sequence + "01" + "%0.2X" % len(trusted_input_2.data) + hexlify(trusted_input_2.data).decode("utf-8") + "00" + "00", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len + "ffffffff" # spend output script + sequence + ] + + packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + + packet = "e0448000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + +################# HASH INPUT FINALIZE WITH CHANGE ######################### +def test_decred_finalize_1(client, firmware, navigator): + packets = [ + "058000002c8000002A800000000000000100000002", # change address bip44 path (size + path) + # "02c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac", #num output + amount + script version + new lock script + same for change addr + "02c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac", + # "00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac" #num output + amount + script version + new lock script + same for change addr + ] + + + packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + # result = dongle.exchange(bytearray.fromhex(packets[0])) + + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:-1]: + packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + + packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] + + with client.exchange_async_raw(data=bytearray.fromhex(packet)) as r: + if firmware.device == "fat": + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.USE_CASE_REVIEW_CONFIRM)]) + if firmware.device in ["nanox","nanosp"]: + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + if firmware.device == "nanos": + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + + +################# HASH SIGN N°1 ######################### +def test_decred_sign_1(client, firmware, navigator): + packets = [ + "058000002c8000002A800000000000000100000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type + ] + + packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + + packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + expected = "3045022100ce8f37f615e60bd604b5c2e78a64068e0fc00a2fd06932060f27bc1e804ba90b02204f72ae4161f8935504d04242a5841b45e8f2776c22655aa3ac7f430f196af03801" + + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % ( expected,hexlify(result.data).decode("utf-8") )) + exit() + + +################# ######################### +################# WITNESS N°2 ######################### +################# ######################### + +################# HASH INPUT START N°2 ######################### +def test_decred_input_start_2(client, firmware, navigator): + packets = [ + "0100000002",#version + number of input + "01" + "%0.2X" % len(trusted_input_1.data) + hexlify(trusted_input_1.data).decode("utf-8") + "00" + "00", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len + "ffffffff", # spend output script + sequence + "01" + "%0.2X" % len(trusted_input_2.data) + hexlify(trusted_input_2.data).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len + "76a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888acffffffff" # spend output script + sequence + ] + + packets[0] = "e0440080" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + # result = dongle.exchange(bytearray.fromhex(packets[0])) + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + + packet = "e0448080" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + +################# HASH INPUT FINALIZE WITH CHANGE N°2 ######################### +def test_decred_finalize_2(client, firmware, navigator): + packets = [ + # "058000002c8000002A800000000000000100000002", # change address bip44 path (size + path) + "02c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac" #num output + amount + script version + new lock script + same for change addr + ] + + # packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + # # result = dongle.exchange(bytearray.fromhex(packets[0])) + # result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + # unused in this case, but useful when packet is splitted in smaller ones + for packet in packets[1:-1]: + packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + # result = dongle.exchange(bytearray.fromhex(packet)) + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + + packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] + # result = dongle.exchange(bytearray.fromhex(packet)) + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + + +################# HASH SIGN N°2 ######################### +def test_decred_sign_2(client, firmware, navigator): + packets = [ + "058000002c8000002A800000000000000000000002000000000000000001" #signing key path len + path + lock time + expiry + sighash type + ] + + packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] + + result = client.exchange_raw(data=bytearray.fromhex(packets[0])) + + for packet in packets[1:]: + print(YOLO) + packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet + # result = dongle.exchange(bytearray.fromhex(packet)) + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + expected = "3144022041b371311dc2f2dc72b83e8249d3fc0f53f6bfc9ccdb214eeea7b35914ba187602200de4313f2dca0aa2ca857afb65e06d693128e6e4b9b127eff018ddcfe98c462e01" + + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot: %s\n" % (expected,hexlify(result.data).decode("utf-8"))) + exit() + + + +''' +APDU EXCHANGE RECAP: + +HID => e042000009000000000100000001 +HID <= 9000 +HID => e042800026334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b180401000000006b +HID <= 9000 +HID => e04280006f4830450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01210306c8988cab4694d1969c77ee5253e6ed5de7368f3f7713e3d5c512b8fd312562ffffffff +HID <= 9000 +HID => e04280000102 +HID <= 9000 +HID => e042800024ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac +HID <= 9000 +HID => e042800024c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac +HID <= 9000 +HID => e0428000080000000000000000 +HID <= 320016c59e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000598355bee9a1e5769000 +HID => e042000009000000010100000001 +HID <= 9000 +HID => e042800026334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b180401000000006b +HID <= 9000 +HID => e04280006f4830450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01210306c8988cab4694d1969c77ee5253e6ed5de7368f3f7713e3d5c512b8fd312562ffffffff +HID <= 9000 +HID => e04280000102 +HID <= 9000 +HID => e042800024ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288ac +HID <= 9000 +HID => e042800024c0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac +HID <= 9000 +HID => e0428000080000000000000000 +HID <= 3200dcac9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000f0d368a53f42bdcd9000 +HID => e0440000050100000002 +HID <= 9000 +HID => e04480003c0138320016c59e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000598355bee9a1e5760019 +HID <= 9000 +HID => e04480001d76a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acffffffff +HID <= 9000 +HID => e04480003c01383200dcac9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000f0d368a53f42bdcd0000 +HID <= 9000 +HID => e044800004ffffffff +HID <= 9000 +HID => e04aff0015058000002c8000002a800000000000000100000002 +HID <= 9000 +HID => e04a80004902c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac +HID <= 00009000 +HID => e04800001e058000002c8000002a800000000000000100000001000000000000000001 +HID <= 3045022100ce8f37f615e60bd604b5c2e78a64068e0fc00a2fd06932060f27bc1e804ba90b02204f72ae4161f8935504d04242a5841b45e8f2776c22655aa3ac7f430f196af038019000 +HID => e0440080050100000002 +HID <= 9000 +HID => e04480803c0138320016c59e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000598355bee9a1e5760000 +HID <= 9000 +HID => e044808004ffffffff +HID <= 9000 +HID => e04480803c01383200dcac9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d01000000c0cf6a0000000000f0d368a53f42bdcd0019 +HID <= 9000 +HID => e04480801d76a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888acffffffff +HID <= 9000 +HID => e04a80004902c03b0e000000000000001976a914a6b939449096f2595113b659e55df41bbd236b5e88ac00127a000000000000001976a91498d35df43b654993f16e3f9979678b0eb941ea8d88ac +HID <= 00009000 +HID => e04800001e058000002c8000002a800000000000000000000002000000000000000001 +HID <= 3144022041b371311dc2f2dc72b83e8249d3fc0f53f6bfc9ccdb214eeea7b35914ba187602200de4313f2dca0aa2ca857afb65e06d693128e6e4b9b127eff018ddcfe98c462e019000 +''' \ No newline at end of file diff --git a/test/test_sign_message.py b/test/test_sign_message.py new file mode 100755 index 0000000..3a6320a --- /dev/null +++ b/test/test_sign_message.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +#******************************************************************************* +#* Ledger App +#* (c) 2016-2019 Ledger +#* +#* 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. +#******************************************************************************** +from ragger.backend import RaisePolicy +from ragger.navigator import NavInsID, NavIns +from binascii import hexlify +import struct + +################# SIGN MESSAGE ######################### +def test_decred_sign_message(client, firmware, navigator): + client.raise_policy = RaisePolicy.RAISE_NOTHING + + magic = "\x18Bitcoin Signed Message:\n" + message = "Message to be signed" + data = magic + chr(len(message)) + message + hex_str_data = hexlify(bytes(data,'ascii' )) + hex_str_sign_msg = b'058000002c8000002A800000000000000100000001' + hexlify(struct.pack('>h', int(len(hex_str_data.decode('ascii'))/2))) + hex_str_data + str_sign_msg = hex_str_sign_msg.decode('ascii') + + packet = "e04e0001" + hexlify(bytes([int(len(str_sign_msg)/2)])).decode("utf-8") + str_sign_msg + result = client.exchange_raw(data=bytearray.fromhex(packet)) + + packet = "e04e80000100" + with client.exchange_async_raw(data=bytearray.fromhex(packet)) as r: + if firmware.device == "fat": + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) + navigator.navigate([NavIns(id=NavInsID.USE_CASE_REVIEW_CONFIRM)]) + if firmware.device in ["nanox","nanosp"]: + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) + if firmware.device == "nanos": + navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) + + # expected = "9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000" + # # expected = "7dfed275d5fb94c2b7fd0a0e92f0b62e8324829c40dba2b09231b7763ab43c5700000000ac211e0000000000" + # if expected not in hexlify(result.data).decode("utf-8"): + # print("Error:\nExpected:%s\nGot: %s\n" % (expected,hexlify(result.data[4:-8]).decode("utf-8"))) + # exit() From 587028d0bed115838b3ca477e6a74c14dab394d2 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 11:10:33 +0200 Subject: [PATCH 19/41] Update Stax target name and makefile. --- Makefile | 20 ++++++++++---------- src/main.c | 12 ++++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index ab3f366..c19303e 100755 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ DEFINES += $(DEFINES_LIB) ifeq ($(TARGET_NAME),TARGET_NANOS) ICONNAME=nanos_app_$(COIN).gif -else ifeq ($(TARGET_NAME),TARGET_FATSTACKS) +else ifeq ($(TARGET_NAME),TARGET_STAX) ICONNAME=stax_app_$(COIN).bmp else ICONNAME=nanox_app_$(COIN).gif @@ -94,20 +94,23 @@ DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" DEFINES += UNUSED\(x\)=\(void\)x DEFINES += APPVERSION=\"$(APPVERSION)\" -ifeq ($(TARGET_NAME),TARGET_FATSTACKS) +ifeq ($(TARGET_NAME),TARGET_STAX) + DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += NBGL_QRCODE NBGL_USE_CASE NBGL_PAGE else DEFINES += HAVE_BAGL endif +# BLE ifeq ($(TARGET_NAME),TARGET_NANOX) -DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 -DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE +DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU +else ifeq ($(TARGET_NAME),TARGET_STAX) +DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU endif ifneq ($(TARGET_NAME),TARGET_NANOS) DEFINES += HAVE_GLO096 -ifneq ($(TARGET_NAME),TARGET_FATSTACKS) +ifneq ($(TARGET_NAME),TARGET_STAX) DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 endif DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature @@ -167,14 +170,11 @@ include $(BOLOS_SDK)/Makefile.glyphs APP_SOURCE_PATH += src SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f -ifeq ($(TARGET_NAME),TARGET_FATSTACKS) -SDK_SOURCE_PATH += lib_nbgl/src -SDK_SOURCE_PATH += lib_ux_fatstacks -else +ifneq ($(TARGET_NAME),TARGET_STAX) SDK_SOURCE_PATH += lib_ux qrcode endif -ifeq ($(TARGET_NAME),TARGET_NANOX) +ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl endif diff --git a/src/main.c b/src/main.c index 3a43fe3..d18fd8e 100644 --- a/src/main.c +++ b/src/main.c @@ -34,7 +34,7 @@ #define __NAME3(a, b, c) a##b##c #define NAME3(a, b, c) __NAME3(a, b, c) -#ifndef TARGET_FATSTACKS +#ifndef TARGET_STAX bagl_element_t tmp_element; #endif @@ -52,13 +52,13 @@ unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; #define COLOR_GRAY 0x999999 #define COLOR_LIGHT_GRAY 0xEEEEEE -#ifndef TARGET_FATSTACKS +#ifndef TARGET_STAX unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e); unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e); #endif void ui_idle(void); -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_FATSTACKS) +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) #include "ux.h" ux_state_t G_ux; bolos_ux_params_t G_ux_params; @@ -66,7 +66,7 @@ bolos_ux_params_t G_ux_params; ux_state_t ux; #endif // TARGET_NANOX || TARGET_NANOS2 -#ifndef TARGET_FATSTACKS +#ifndef TARGET_STAX // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { @@ -111,7 +111,7 @@ unsigned char io_event(unsigned char channel) { UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); break; -#ifndef TARGET_FATSTACKS +#ifndef TARGET_STAX case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); break; @@ -127,7 +127,7 @@ unsigned char io_event(unsigned char channel) { default: UX_DEFAULT_EVENT(); break; -#ifndef TARGET_FATSTACKS +#ifndef TARGET_STAX case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: UX_DISPLAYED_EVENT({}); break; From 85f38a4329879bfb0cc089bed0b128a334d95316 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 11:10:56 +0200 Subject: [PATCH 20/41] Fix warnings + updates for latest SDK. --- src/btchip_transaction.c | 4 ++++ src/main.c | 1 + src/ui/pubkey/ui_pubkey_nbgl.c | 6 +++--- src/ui/transaction/ui_transaction_nbgl.c | 16 ++++++++-------- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 09092b4..74d1723 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -184,6 +184,7 @@ void transaction_parse(unsigned char parseMode) { BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { @@ -363,6 +364,7 @@ void transaction_parse(unsigned char parseMode) { BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { unsigned char dataAvailable; @@ -456,6 +458,7 @@ void transaction_parse(unsigned char parseMode) { BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { if (btchip_context_D.transactionContext @@ -499,6 +502,7 @@ void transaction_parse(unsigned char parseMode) { BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { unsigned char dataAvailable; diff --git a/src/main.c b/src/main.c index d18fd8e..609c471 100644 --- a/src/main.c +++ b/src/main.c @@ -124,6 +124,7 @@ unsigned char io_event(unsigned char channel) { THROW(EXCEPTION_IO_RESET); } // no break is intentional + __attribute__((fallthrough)); default: UX_DEFAULT_EVENT(); break; diff --git a/src/ui/pubkey/ui_pubkey_nbgl.c b/src/ui/pubkey/ui_pubkey_nbgl.c index ee8a543..cea2cb3 100644 --- a/src/ui/pubkey/ui_pubkey_nbgl.c +++ b/src/ui/pubkey/ui_pubkey_nbgl.c @@ -100,7 +100,7 @@ void ui_display_public_key(unsigned char* derivation_path) { sizeof(choice_text), "WARNING !\nThe derivation path is\nunusual :\n%s", vars.tmp_warning.derivation_path); - nbgl_useCaseChoice(choice_text,"Reject if you're not sure","Reject","Continue",warningChoiceClbk); + nbgl_useCaseChoice(NULL, choice_text,"Reject if you're not sure","Reject","Continue",warningChoiceClbk); } else { @@ -111,7 +111,7 @@ void ui_display_public_key(unsigned char* derivation_path) { void ui_display_request_pubkey_approval(void) { display_type = EXPORT_REQUEST; - nbgl_useCaseChoice("Export public key ?",NULL,"Export","Cancel",confirmationChoiceClbk); + nbgl_useCaseChoice(NULL,"Export public key ?",NULL,"Export","Cancel",confirmationChoiceClbk); } void ui_display_token(void) @@ -122,7 +122,7 @@ void ui_display_token(void) sizeof(choice_text), "Approve token :\n%s", (char*)G_io_apdu_buffer+200); - nbgl_useCaseChoice(choice_text,NULL,"Approve","Reject",confirmationChoiceClbk); + nbgl_useCaseChoice(NULL,choice_text,NULL,"Approve","Reject",confirmationChoiceClbk); } #endif // HAVE_NBGL diff --git a/src/ui/transaction/ui_transaction_nbgl.c b/src/ui/transaction/ui_transaction_nbgl.c index 93badaf..72ba0ff 100644 --- a/src/ui/transaction/ui_transaction_nbgl.c +++ b/src/ui/transaction/ui_transaction_nbgl.c @@ -37,12 +37,12 @@ typedef enum { } transaction_type_t; typedef struct { - char* reviewStart; - char* reviewCancel; - char* finishOk; - char* finishCancel; - char* choiceCancel; - char* choiceGoBack; + const char* reviewStart; + const char* reviewCancel; + const char* finishOk; + const char* finishCancel; + const char* choiceCancel; + const char* choiceGoBack; } messages_t; static nbgl_layoutTagValueList_t pairList; @@ -93,7 +93,7 @@ static void reviewChoice(bool confirm) { static void rejectUseCaseChoice(void) { - nbgl_useCaseChoice(msgs.choiceCancel,NULL,"Yes, cancel",msgs.choiceGoBack,rejectChoice); + nbgl_useCaseChoice(NULL,msgs.choiceCancel,NULL,"Yes, cancel",msgs.choiceGoBack,rejectChoice); } static void displayTransaction(void) { @@ -221,6 +221,6 @@ void ui_tx_request_change_path_approval(unsigned char* change_path) sizeof(genericText), "WARNING !\nThe change path is\nunusual :\n%s", vars.tmp_warning.derivation_path); - nbgl_useCaseChoice(genericText,"Reject if you're not sure","Reject","Continue",changePathWarningChoice); + nbgl_useCaseChoice(NULL,genericText,"Reject if you're not sure","Reject","Continue",changePathWarningChoice); } #endif From 3a656510f52ba8008028253130e1301097bc09e9 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 12:14:53 +0200 Subject: [PATCH 21/41] Lint --- src/btchip.c | 58 +- src/btchip_apdu_get_coin_version.c | 40 +- src/btchip_apdu_get_trusted_input.c | 68 +- src/btchip_apdu_get_wallet_public_key.c | 106 +-- src/btchip_apdu_hash_input_finalize_full.c | 377 ++++----- src/btchip_apdu_hash_input_start.c | 53 +- src/btchip_apdu_hash_sign.c | 69 +- src/btchip_apdu_sign_message.c | 174 ++-- src/btchip_bagl_extensions.h | 30 +- src/btchip_base58.c | 219 ++--- src/btchip_context.c | 67 +- src/btchip_helpers.c | 213 ++--- src/btchip_transaction.c | 935 ++++++++++----------- src/main.c | 167 ++-- src/ui/main/ui_main_menu.h | 30 +- src/ui/main/ui_main_menu_bagl.c | 182 ++-- src/ui/main/ui_main_menu_nbgl.c | 101 +-- src/ui/pubkey/ui_pubkey.h | 30 +- src/ui/pubkey/ui_pubkey_bagl.c | 424 +++++----- src/ui/pubkey/ui_pubkey_nbgl.c | 119 ++- src/ui/transaction/ui_transaction.h | 30 +- src/ui/transaction/ui_transaction_bagl.c | 660 +++++++-------- src/ui/transaction/ui_transaction_nbgl.c | 142 ++-- src/ui/ui_shared.c | 253 +++--- src/ui/ui_shared.h | 87 +- 25 files changed, 2268 insertions(+), 2366 deletions(-) diff --git a/src/btchip.c b/src/btchip.c index c76db8d..61168b0 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "os.h" @@ -46,8 +46,7 @@ void app_dispatch(void) { cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; ins = G_io_apdu_buffer[ISO_OFFSET_INS]; for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { - if ((cla == DISPATCHER_CLA[dispatched]) && - (ins == DISPATCHER_INS[dispatched])) { + if ((cla == DISPATCHER_CLA[dispatched]) && (ins == DISPATCHER_INS[dispatched])) { break; } } @@ -56,8 +55,7 @@ void app_dispatch(void) { goto sendSW; } if (DISPATCHER_DATA_IN[dispatched]) { - if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || - btchip_context_D.inLength - 5 == 0) { + if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || btchip_context_D.inLength - 5 == 0) { btchip_context_D.sw = BTCHIP_SW_INCORRECT_LENGTH; goto sendSW; } @@ -65,21 +63,19 @@ void app_dispatch(void) { // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); } // call the apdu handler - btchip_context_D.sw = ((apduProcessingFunction)PIC( - DISPATCHER_FUNCTIONS[dispatched]))(); + btchip_context_D.sw = + ((apduProcessingFunction) PIC(DISPATCHER_FUNCTIONS[dispatched]))(); // an APDU has been replied. request for power off time extension from the // common ux #ifdef IO_APP_ACTIVITY IO_APP_ACTIVITY(); -#endif // IO_APP_ACTIVITY +#endif // IO_APP_ACTIVITY sendSW: // prepare SW after replied data - G_io_apdu_buffer[btchip_context_D.outLength] = - (btchip_context_D.sw >> 8); - G_io_apdu_buffer[btchip_context_D.outLength + 1] = - (btchip_context_D.sw & 0xff); + G_io_apdu_buffer[btchip_context_D.outLength] = (btchip_context_D.sw >> 8); + G_io_apdu_buffer[btchip_context_D.outLength + 1] = (btchip_context_D.sw & 0xff); btchip_context_D.outLength += 2; } CATCH(EXCEPTION_IO_RESET) { @@ -99,7 +95,7 @@ void app_dispatch(void) { } void app_main(void) { - explicit_bzero(G_io_apdu_buffer, 255); // paranoia + explicit_bzero(G_io_apdu_buffer, 255); // paranoia // Process the incoming APDUs @@ -107,14 +103,12 @@ void app_main(void) { btchip_context_D.outLength = 0; btchip_context_D.io_flags = 0; for (;;) { - // explicit_bzero(G_io_apdu_buffer, 255); // paranoia // receive the whole apdu using the 7 bytes headers (ledger transport) - btchip_context_D.inLength = - io_exchange(CHANNEL_APDU | btchip_context_D.io_flags, - // use the previous outlength as the reply - btchip_context_D.outLength); + btchip_context_D.inLength = io_exchange(CHANNEL_APDU | btchip_context_D.io_flags, + // use the previous outlength as the reply + btchip_context_D.outLength); app_dispatch(); diff --git a/src/btchip_apdu_get_coin_version.c b/src/btchip_apdu_get_coin_version.c index c717a65..5749c09 100644 --- a/src/btchip_apdu_get_coin_version.c +++ b/src/btchip_apdu_get_coin_version.c @@ -1,24 +1,24 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -#define P1_VERSION_ONLY 0x00 +#define P1_VERSION_ONLY 0x00 #define P1_VERSION_COINID 0x01 unsigned short btchip_apdu_get_coin_version() { @@ -30,12 +30,12 @@ unsigned short btchip_apdu_get_coin_version() { G_io_apdu_buffer[offset++] = btchip_context_D.payToScriptHashVersion; G_io_apdu_buffer[offset++] = btchip_context_D.coinFamily; G_io_apdu_buffer[offset++] = btchip_context_D.coinIdLength; - memmove(G_io_apdu_buffer + offset, btchip_context_D.coinId, - btchip_context_D.coinIdLength); + memmove(G_io_apdu_buffer + offset, btchip_context_D.coinId, btchip_context_D.coinIdLength); offset += btchip_context_D.coinIdLength; G_io_apdu_buffer[offset++] = btchip_context_D.shortCoinIdLength; - memmove(G_io_apdu_buffer + offset, btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); + memmove(G_io_apdu_buffer + offset, + btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); offset += btchip_context_D.shortCoinIdLength; btchip_context_D.outLength = offset; diff --git a/src/btchip_apdu_get_trusted_input.c b/src/btchip_apdu_get_trusted_input.c index e24af22..aabe21e 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/btchip_apdu_get_trusted_input.c @@ -1,25 +1,25 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 -#define GET_TRUSTED_INPUT_P1_NEXT 0x80 +#define GET_TRUSTED_INPUT_P1_NEXT 0x80 #define TRUSTEDINPUT_SIZE 48 @@ -29,44 +29,39 @@ unsigned short btchip_apdu_get_trusted_input() { unsigned char trustedInputSignature[32]; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize btchip_context_D.transactionTargetInput = btchip_read_u32(G_io_apdu_buffer + ISO_OFFSET_CDATA, 1, 0); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.trustedInputProcessed = 0; btchip_context_D.transactionContext.consumeP2SH = 0; btchip_set_check_internal_structure_integrity(1); dataOffset = 4; btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; - } - else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { + } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { return BTCHIP_SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00) { return BTCHIP_SW_INCORRECT_P1_P2; } - btchip_context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; + btchip_context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; btchip_context_D.transactionDataRemaining = apduLength - dataOffset; transaction_parse(PARSE_MODE_TRUSTED_INPUT); if (btchip_context_D.transactionContext.transactionState == BTCHIP_TRANSACTION_PARSED) { - //unsigned char targetHash[32]; + // unsigned char targetHash[32]; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); if (!btchip_context_D.trustedInputProcessed) { // Output was not found return BTCHIP_SW_INCORRECT_DATA; } - //cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, + // cx_hash(&btchip_context_D.transactionHashPrefix.header, CX_LAST, // (unsigned char *)NULL, 0, targetHash); // Otherwise prepare @@ -75,18 +70,21 @@ unsigned short btchip_apdu_get_trusted_input() { G_io_apdu_buffer[1] = 0x00; blake256_Final(&btchip_context_D.transactionHashPrefix, G_io_apdu_buffer + 4); - //cx_hash(&btchip_context_D.transactionHashPrefix, CX_LAST, (unsigned char *)NULL, 0, G_io_apdu_buffer + 4); + // cx_hash(&btchip_context_D.transactionHashPrefix, CX_LAST, (unsigned char *)NULL, 0, + // G_io_apdu_buffer + 4); - btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, - btchip_context_D.transactionTargetInput); + btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, btchip_context_D.transactionTargetInput); memmove(G_io_apdu_buffer + 4 + 32 + 4, - btchip_context_D.transactionContext.transactionAmount, 8); + btchip_context_D.transactionContext.transactionAmount, + 8); cx_hmac_sha256((const uint8_t*) N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), G_io_apdu_buffer, - TRUSTEDINPUT_SIZE, trustedInputSignature, 32); - memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, - 8); + sizeof(N_btchip.bkp.trustedinput_key), + G_io_apdu_buffer, + TRUSTEDINPUT_SIZE, + trustedInputSignature, + 32); + memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, 8); btchip_context_D.outLength = 0x38; } diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index b4e2d56..ba69a0e 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -21,8 +21,8 @@ #include "btchip_bagl_extensions.h" #include "ui_pubkey.h" -#define P1_NO_DISPLAY 0x00 -#define P1_DISPLAY 0x01 +#define P1_NO_DISPLAY 0x00 +#define P1_DISPLAY 0x01 #define P1_REQUEST_TOKEN 0x02 #define P2_LEGACY 0x00 @@ -35,38 +35,40 @@ unsigned short btchip_apdu_get_wallet_public_key() { uint32_t request_token; unsigned char chainCode[32]; bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY); - bool display_request_token = N_btchip.pubKeyRequestRestriction && (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && G_io_apdu_media == IO_APDU_MEDIA_U2F; - bool require_user_approval = N_btchip.pubKeyRequestRestriction && !(display_request_token || display) && G_io_apdu_media == IO_APDU_MEDIA_U2F; - + bool display_request_token = N_btchip.pubKeyRequestRestriction && + (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && + G_io_apdu_media == IO_APDU_MEDIA_U2F; + bool require_user_approval = N_btchip.pubKeyRequestRestriction && + !(display_request_token || display) && + G_io_apdu_media == IO_APDU_MEDIA_U2F; switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { - case P1_NO_DISPLAY: - case P1_DISPLAY: - case P1_REQUEST_TOKEN: - break; - default: - return BTCHIP_SW_INCORRECT_P1_P2; + case P1_NO_DISPLAY: + case P1_DISPLAY: + case P1_REQUEST_TOKEN: + break; + default: + return BTCHIP_SW_INCORRECT_P1_P2; } switch (G_io_apdu_buffer[ISO_OFFSET_P2]) { - case P2_LEGACY: - break; - default: - return BTCHIP_SW_INCORRECT_P1_P2; + case P2_LEGACY: + break; + default: + return BTCHIP_SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_LC] < 0x01) { return BTCHIP_SW_INCORRECT_LENGTH; } - memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); + memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); - if(display_request_token){ - uint8_t request_token_offset = ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA]*4 + 1; + if (display_request_token) { + uint8_t request_token_offset = + ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA] * 4 + 1; request_token = btchip_read_u32(G_io_apdu_buffer + request_token_offset, true, false); } - if (os_global_pin_is_validated() != BOLOS_UX_OK) { return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; } @@ -82,14 +84,14 @@ unsigned short btchip_apdu_get_wallet_public_key() { keyLength = 33; } - memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, - sizeof(btchip_public_key_D.W)); + memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W, sizeof(btchip_public_key_D.W)); - keyLength = btchip_public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - G_io_apdu_buffer + 67, // OUT - 150, // MAXOUTLEN - btchip_context_D.payToAddressVersion, 0); + keyLength = btchip_public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN + keyLength, // INLEN + G_io_apdu_buffer + 67, // OUT + 150, // MAXOUTLEN + btchip_context_D.payToAddressVersion, + 0); G_io_apdu_buffer[66] = keyLength; PRINTF("Length %d\n", keyLength); @@ -99,8 +101,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { } // output chain code - memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, - sizeof(chainCode)); + memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, sizeof(chainCode)); btchip_context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); if (display) { @@ -112,20 +113,20 @@ unsigned short btchip_apdu_get_wallet_public_key() { G_io_apdu_buffer[200 + keyLength] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; ui_display_public_key(keyPath); - } - // If the token requested has already been approved in a previous call, the source is trusted so don't ask for approval again - else if(display_request_token && - (!btchip_context_D.has_valid_token || memcmp(&request_token, btchip_context_D.last_token, 4))) { + } + // If the token requested has already been approved in a previous call, the source is trusted so + // don't ask for approval again + else if (display_request_token && (!btchip_context_D.has_valid_token || + memcmp(&request_token, btchip_context_D.last_token, 4))) { // disable the has_valid_token flag and store the new token btchip_context_D.has_valid_token = false; memcpy(btchip_context_D.last_token, &request_token, 4); // Hax, avoid wasting space - snprintf((char*)G_io_apdu_buffer + 200, 9, "%08X", request_token); + snprintf((char*) G_io_apdu_buffer + 200, 9, "%08X", request_token); G_io_apdu_buffer[200 + 8] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; ui_display_token(); - } - else if(require_user_approval) { + } else if (require_user_approval) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; ui_display_request_pubkey_approval(); } @@ -137,8 +138,7 @@ void btchip_bagl_user_action_display(unsigned char confirming) { unsigned short sw = BTCHIP_SW_OK; // confirm and finish the apdu exchange //spaghetti if (confirming) { - btchip_context_D.outLength -= - 2; // status was already set by the last call + btchip_context_D.outLength -= 2; // status was already set by the last call } else { sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 0131339..c17ca81 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ // TODO Trustlet, BAGL : process each output separately. // review nvm_write policy @@ -23,11 +23,11 @@ #include "btchip_bagl_extensions.h" #include "ui_transaction.h" -#define FINALIZE_P1_MORE 0x00 -#define FINALIZE_P1_LAST 0x80 +#define FINALIZE_P1_MORE 0x00 +#define FINALIZE_P1_LAST 0x80 #define FINALIZE_P1_CHANGEINFO 0xFF -#define FLAG_SIGNATURE 0x01 +#define FLAG_SIGNATURE 0x01 #define FLAG_CHANGE_VALIDATED 0x80 extern uint8_t prepare_full_output(uint8_t checkOnly); @@ -35,8 +35,7 @@ extern uint8_t prepare_full_output(uint8_t checkOnly); static void btchip_apdu_hash_input_finalize_full_reset(void) { btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - explicit_bzero(btchip_context_D.totalOutputAmount, - sizeof(btchip_context_D.totalOutputAmount)); + explicit_bzero(btchip_context_D.totalOutputAmount, sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; btchip_set_check_internal_structure_integrity(1); } @@ -44,7 +43,7 @@ static void btchip_apdu_hash_input_finalize_full_reset(void) { static bool check_output_displayable() { PRINTF("Check if output is displayable\n"); bool displayable = true; - unsigned char amount[8], isOpReturn, isP2sh, j,nullAmount = 1; + unsigned char amount[8], isOpReturn, isP2sh, j, nullAmount = 1; unsigned char isOpCreate, isOpCall; for (j = 0; j < 8; j++) { @@ -56,30 +55,27 @@ static bool check_output_displayable() { if (!nullAmount) { btchip_swap_bytes(amount, btchip_context_D.currentOutput, 8); transaction_amount_add_be(btchip_context_D.totalOutputAmount, - btchip_context_D.totalOutputAmount, amount); + btchip_context_D.totalOutputAmount, + amount); } - isOpReturn = - btchip_output_script_is_op_return(btchip_context_D.currentOutput + 8 + 2); // +2 for script version, decred particularity + isOpReturn = btchip_output_script_is_op_return( + btchip_context_D.currentOutput + 8 + 2); // +2 for script version, decred particularity isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + 8 + 2); - isOpCreate = - btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); - isOpCall = - btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); + isOpCreate = btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); + isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); - if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8 + 2) && - !isP2sh && !(nullAmount && isOpReturn)) { + if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8 + 2) && !isP2sh && + !(nullAmount && isOpReturn)) { PRINTF("Error: Unrecognized input script\n"); THROW(EXCEPTION); } if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { bool changeFound = false; unsigned char addressOffset = - (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (!isP2sh && - memcmp(btchip_context_D.currentOutput + 8 + 2 + addressOffset, - btchip_context_D.tmpCtx.output.changeAddress + 1, - 20) == 0) { + (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (!isP2sh && memcmp(btchip_context_D.currentOutput + 8 + 2 + addressOffset, + btchip_context_D.tmpCtx.output.changeAddress + 1, + 20) == 0) { changeFound = true; } @@ -101,99 +97,96 @@ static bool handle_output_state() { btchip_context_D.discardSize = 0; bool processed = false; switch (btchip_context_D.outputParsingState) { - case BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS: { - // this is default init state - btchip_context_D.totalOutputs = 0; - if (btchip_context_D.currentOutputOffset < 1) { - break; - } - if (btchip_context_D.currentOutput[0] < 0xFD) { - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_context_D.currentOutput[0]; - discardSize = 1; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } - if (btchip_context_D.currentOutput[0] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 3) { + case BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS: { + // this is default init state + btchip_context_D.totalOutputs = 0; + if (btchip_context_D.currentOutputOffset < 1) { break; } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - (btchip_context_D.currentOutput[2] << 8) | - btchip_context_D.currentOutput[1]; - discardSize = 3; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else if (btchip_context_D.currentOutput[0] == 0xFE) { - if (btchip_context_D.currentOutputOffset < 5) { + if (btchip_context_D.currentOutput[0] < 0xFD) { + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + btchip_context_D.currentOutput[0]; + discardSize = 1; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; break; } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_read_u32(btchip_context_D.currentOutput + 1, 0, 0); - discardSize = 5; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else { - THROW(EXCEPTION); - } - } break; + if (btchip_context_D.currentOutput[0] == 0xFD) { + if (btchip_context_D.currentOutputOffset < 3) { + break; + } + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + (btchip_context_D.currentOutput[2] << 8) | btchip_context_D.currentOutput[1]; + discardSize = 3; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else if (btchip_context_D.currentOutput[0] == 0xFE) { + if (btchip_context_D.currentOutputOffset < 5) { + break; + } + btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = + btchip_read_u32(btchip_context_D.currentOutput + 1, 0, 0); + discardSize = 5; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else { + THROW(EXCEPTION); + } + } break; - case BTCHIP_OUTPUT_PARSING_OUTPUT: { - PRINTF("BTCHIP_OUTPUT_PARSING_OUTPUT:\n"); + case BTCHIP_OUTPUT_PARSING_OUTPUT: { + PRINTF("BTCHIP_OUTPUT_PARSING_OUTPUT:\n"); - unsigned int scriptSize; - if (btchip_context_D.currentOutputOffset < 9) { - break; - } - if (btchip_context_D.currentOutput[8+2] < 0xFD) { - scriptSize = btchip_context_D.currentOutput[8+2]; - discardSize = 1; - } else if (btchip_context_D.currentOutput[8+2] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 9 + 2) { + unsigned int scriptSize; + if (btchip_context_D.currentOutputOffset < 9) { + break; + } + if (btchip_context_D.currentOutput[8 + 2] < 0xFD) { + scriptSize = btchip_context_D.currentOutput[8 + 2]; + discardSize = 1; + } else if (btchip_context_D.currentOutput[8 + 2] == 0xFD) { + if (btchip_context_D.currentOutputOffset < 9 + 2) { + break; + } + scriptSize = btchip_read_u32(btchip_context_D.currentOutput + 9, 0, 0); + discardSize = 3; + } else { + // Unrealistically large script + THROW(EXCEPTION); + } + if (btchip_context_D.currentOutputOffset < 8 + 2 + discardSize + scriptSize) { + discardSize = 0; break; } - scriptSize = - btchip_read_u32(btchip_context_D.currentOutput + 9, 0, 0); - discardSize = 3; - } else { - // Unrealistically large script - THROW(EXCEPTION); - } - if (btchip_context_D.currentOutputOffset < - 8 + 2 + discardSize + scriptSize) { - discardSize = 0; - break; - } - processed = true; + processed = true; - discardSize += 8 + 2 + scriptSize; + discardSize += 8 + 2 + scriptSize; - if (check_output_displayable()) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; + if (check_output_displayable()) { + btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - // The output can be processed by the UI + // The output can be processed by the UI - btchip_context_D.discardSize = discardSize; - discardSize = 0; - } else { - btchip_context_D.remainingOutputs--; - PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); - } - } break; + btchip_context_D.discardSize = discardSize; + discardSize = 0; + } else { + btchip_context_D.remainingOutputs--; + PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); + } + } break; - default: - THROW(EXCEPTION); + default: + THROW(EXCEPTION); } if (discardSize != 0) { PRINTF("discard %d bytes from output\n", discardSize); memmove(btchip_context_D.currentOutput, - btchip_context_D.currentOutput + discardSize, - btchip_context_D.currentOutputOffset - discardSize); + btchip_context_D.currentOutput + discardSize, + btchip_context_D.currentOutputOffset - discardSize); btchip_context_D.currentOutputOffset -= discardSize; } @@ -214,8 +207,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && - (p1 != FINALIZE_P1_CHANGEINFO)) { + if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && (p1 != FINALIZE_P1_CHANGEINFO)) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -242,39 +234,35 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } - explicit_bzero(transactionSummary, - sizeof(btchip_transaction_summary_t)); + explicit_bzero(transactionSummary, sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { // Called with no change path, abort, should be prevented on // the client side goto return_OK; } memmove(transactionSummary->summarydata.keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); - btchip_private_derive_keypair( - transactionSummary->summarydata.keyPath, 1, NULL); - if (((N_btchip.bkp.config.options & - BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { + G_io_apdu_buffer + ISO_OFFSET_CDATA, + MAX_BIP32_PATH_LENGTH); + btchip_private_derive_keypair(transactionSummary->summarydata.keyPath, 1, NULL); + if (((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { keyLength = 65; } else { btchip_compress_public_key_value(btchip_public_key_D.W); keyLength = 33; } - btchip_public_key_hash160( - btchip_public_key_D.W, // IN - keyLength, // INLEN - transactionSummary->summarydata.changeAddress + 1 // OUT + btchip_public_key_hash160(btchip_public_key_D.W, // IN + keyLength, // INLEN + transactionSummary->summarydata.changeAddress + 1 // OUT ); - memmove( - btchip_context_D.tmpCtx.output.changeAddress, - transactionSummary->summarydata.changeAddress, - sizeof(transactionSummary->summarydata.changeAddress)); + memmove(btchip_context_D.tmpCtx.output.changeAddress, + transactionSummary->summarydata.changeAddress, + sizeof(transactionSummary->summarydata.changeAddress)); btchip_context_D.tmpCtx.output.changeInitialized = 1; btchip_context_D.tmpCtx.output.changeAccepted = 0; - // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval - if(bip44_derivation_guard(transactionSummary->summarydata.keyPath, true)) { + // if the bip44 change path provided is not canonical or its index are unsual, ask + // for user approval + if (bip44_derivation_guard(transactionSummary->summarydata.keyPath, true)) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_context_D.outputParsingState = BTCHIP_BIP44_CHANGE_PATH_VALIDATION; ui_tx_request_change_path_approval(transactionSummary->summarydata.keyPath); @@ -286,10 +274,15 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( // Always update the transaction & authorization hashes with the // given data - PRINTF("Adding to prefix hash:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); - blake256_Update(&btchip_context_D.transactionHashPrefix, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset); - blake256_Update(&btchip_context_D.transactionHashAuthorization, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset); - + PRINTF("Adding to prefix hash:\n%.*H\n", + apduLength - hashOffset, + G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); + blake256_Update(&btchip_context_D.transactionHashPrefix, + G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, + apduLength - hashOffset); + blake256_Update(&btchip_context_D.transactionHashAuthorization, + G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, + apduLength - hashOffset); if (btchip_context_D.transactionContext.firstSigned) { if ((btchip_context_D.currentOutputOffset + apduLength) > @@ -298,23 +291,21 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_INCORRECT_DATA; goto discardTransaction; } - memmove(btchip_context_D.currentOutput + - btchip_context_D.currentOutputOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); + memmove(btchip_context_D.currentOutput + btchip_context_D.currentOutputOffset, + G_io_apdu_buffer + ISO_OFFSET_CDATA, + apduLength); btchip_context_D.currentOutputOffset += apduLength; // Check if the legacy UI can be applied if ((G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_LAST) && - !btchip_context_D.tmpCtx.output.multipleOutput && - prepare_full_output(1)) { + !btchip_context_D.tmpCtx.output.multipleOutput && prepare_full_output(1)) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_HANDLE_LEGACY; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_HANDLE_LEGACY; btchip_context_D.remainingOutputs = 0; } else { // parse outputs until one can be displayed while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) ; // Finalize the TX if necessary @@ -322,8 +313,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( if ((btchip_context_D.remainingOutputs == 0) && (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_FINALIZE_TX; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; } } } @@ -340,15 +330,12 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( blake256_Final(&btchip_context_D.transactionHashAuthorization, authorizationHash); - - if(btchip_context_D.transactionContext.firstSigned) { + if (btchip_context_D.transactionContext.firstSigned) { if (!btchip_context_D.tmpCtx.output.changeInitialized) { - explicit_bzero(transactionSummary, - sizeof(btchip_transaction_summary_t)); + explicit_bzero(transactionSummary, sizeof(btchip_transaction_summary_t)); } - transactionSummary->payToAddressVersion = - btchip_context_D.payToAddressVersion; + transactionSummary->payToAddressVersion = btchip_context_D.payToAddressVersion; transactionSummary->payToScriptHashVersion = btchip_context_D.payToScriptHashVersion; @@ -371,39 +358,36 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( // synchronized) if (btchip_context_D.transactionContext.firstSigned) { memmove(transactionSummary->authorizationHash, - authorizationHash, - sizeof(transactionSummary->authorizationHash)); - goto return_OK; - } else { - if (btchip_secure_memcmp( authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { + sizeof(transactionSummary->authorizationHash)); + goto return_OK; + } else { + if (btchip_secure_memcmp(authorizationHash, + transactionSummary->authorizationHash, + sizeof(transactionSummary->authorizationHash))) { PRINTF("Authorization hash doesn't match the previous one\n"); sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; -discardTransaction: + discardTransaction: CLOSE_TRY; goto catch_discardTransaction; - } - else { + } else { PRINTF("Authorization Hash OK:\n%.*H\n", 32, authorizationHash); } } - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_SIGN_READY; sw = BTCHIP_SW_OK; } CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0x0F); catch_discardTransaction: - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; - memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, - btchip_context_D.currentOutputOffset); + memmove(G_io_apdu_buffer, + btchip_context_D.currentOutput, + btchip_context_D.currentOutputOffset); btchip_context_D.outLength = btchip_context_D.currentOutputOffset; } FINALLY { @@ -416,32 +400,28 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( unsigned short btchip_apdu_hash_input_finalize_full() { PRINTF("state=%d\n", btchip_context_D.outputParsingState); - unsigned short sw = btchip_apdu_hash_input_finalize_full_internal( - &btchip_context_D.transactionSummary); + unsigned short sw = + btchip_apdu_hash_input_finalize_full_internal(&btchip_context_D.transactionSummary); if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { // if the UI reject the processing of the request, then reply // immediately bool status; - if(btchip_context_D.outputParsingState == BTCHIP_BIP44_CHANGE_PATH_VALIDATION) { + if (btchip_context_D.outputParsingState == BTCHIP_BIP44_CHANGE_PATH_VALIDATION) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; return sw; - } - else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { + } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { PRINTF("BAGL finalize tx:\n"); status = ui_tx_finalize(); - } else if (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_HANDLE_LEGACY) { + } else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_HANDLE_LEGACY) { PRINTF("BAGL confirm output legacy:\n"); status = ui_tx_confirm_full_output(); - } - else { + } else { PRINTF("BAGL confirm single output:\n"); status = ui_tx_confirm_single_output(); } if (!status) { btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; sw = BTCHIP_SW_INCORRECT_DATA; } @@ -456,28 +436,22 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { if (confirming) { // Check if all inputs have been confirmed - if (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_PARSING_OUTPUT) { + if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_PARSING_OUTPUT) { btchip_context_D.remainingOutputs--; PRINTF("%d remaining outputs\n", btchip_context_D.remainingOutputs); } while (btchip_context_D.remainingOutputs != 0) { memmove(btchip_context_D.currentOutput, - btchip_context_D.currentOutput + - btchip_context_D.discardSize, - btchip_context_D.currentOutputOffset - - btchip_context_D.discardSize); - btchip_context_D.currentOutputOffset -= - btchip_context_D.discardSize; + btchip_context_D.currentOutput + btchip_context_D.discardSize, + btchip_context_D.currentOutputOffset - btchip_context_D.discardSize); + btchip_context_D.currentOutputOffset -= btchip_context_D.discardSize; btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + while (handle_output_state() && (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) ; if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { if (!ui_tx_confirm_single_output()) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_INCORRECT_DATA; break; } else { @@ -490,15 +464,12 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { } } - if ((btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_PARSING_OUTPUT) && + if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_PARSING_OUTPUT) && (btchip_context_D.remainingOutputs == 0)) { btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; if (!ui_tx_finalize()) { - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_PARSING_NONE; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_INCORRECT_DATA; } else { // Let the UI play @@ -506,22 +477,16 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { } } - if ((btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_FINALIZE_TX) || - (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_HANDLE_LEGACY)) { + if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) || + (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_HANDLE_LEGACY)) { btchip_context_D.transactionContext.firstSigned = 0; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; - + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_SIGN_READY; } - btchip_context_D.outLength -= - 2; // status was already set by the last call + btchip_context_D.outLength -= 2; // status was already set by the last call } else { // Discard transaction - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; btchip_context_D.outLength = 0; } diff --git a/src/btchip_apdu_hash_input_start.c b/src/btchip_apdu_hash_input_start.c index 9b16a26..f4b2e03 100644 --- a/src/btchip_apdu_hash_input_start.c +++ b/src/btchip_apdu_hash_input_start.c @@ -1,44 +1,40 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" -#define P1_FIRST 0x00 -#define P1_NEXT 0x80 -#define P2_NEW 0x00 +#define P1_FIRST 0x00 +#define P1_NEXT 0x80 +#define P2_NEW 0x00 #define P2_CONTINUE 0x80 - unsigned short btchip_apdu_hash_input_start() { unsigned char apduLength; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; PRINTF("\n### HASH_INPUT_START:\n"); - if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { // Initialize - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; - } - else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { + } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -62,17 +58,14 @@ unsigned short btchip_apdu_hash_input_start() { btchip_context_D.transactionContext.relaxed = 0; btchip_set_check_internal_structure_integrity(1); // Initialize for screen pairing - explicit_bzero(&btchip_context_D.tmpCtx.output, - sizeof(btchip_context_D.tmpCtx.output)); + explicit_bzero(&btchip_context_D.tmpCtx.output, sizeof(btchip_context_D.tmpCtx.output)); btchip_context_D.tmpCtx.output.changeAccepted = 1; } - } - else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { + } else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { return BTCHIP_SW_INCORRECT_P1_P2; } - btchip_context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA; + btchip_context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA; btchip_context_D.transactionDataRemaining = apduLength; transaction_parse(PARSE_MODE_SIGNATURE); diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 2824a22..50a3dad 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -21,7 +21,6 @@ #define SIGHASH_ALL 0x01 unsigned short btchip_apdu_hash_sign() { - PRINTF("\n### HASH_SIGN:\n"); unsigned long int lockTime; @@ -34,8 +33,7 @@ unsigned short btchip_apdu_hash_sign() { unsigned short sw; unsigned char keyPath[MAX_BIP32_PATH_LENGTH]; - if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) && - (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { + if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) && (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { return BTCHIP_SW_INCORRECT_P1_P2; } @@ -49,7 +47,8 @@ unsigned short btchip_apdu_hash_sign() { btchip_set_check_internal_structure_integrity(0); if (btchip_context_D.transactionContext.transactionState != BTCHIP_TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", btchip_context_D.transactionContext.transactionState); + PRINTF("Invalid transaction state %d\n", + btchip_context_D.transactionContext.transactionState); sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } @@ -61,8 +60,7 @@ unsigned short btchip_apdu_hash_sign() { CLOSE_TRY; goto catch_discardTransaction; } - memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); + memmove(keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; lockTime = btchip_read_u32(parameters, 1, 0); @@ -72,8 +70,7 @@ unsigned short btchip_apdu_hash_sign() { sighashType = *(parameters++); PRINTF("SighashType: %d\n", sighashType); - if (((N_btchip.bkp.config.options & - BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { + if (((N_btchip.bkp.config.options & BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { // if bitcoin cash OR forkid is set, then use the fork id if (G_coin_config->forkid) { #define SIGHASH_FORKID 0x40 @@ -105,8 +102,9 @@ unsigned short btchip_apdu_hash_sign() { btchip_write_u32_le(dataBuffer + 4, expiry); PRINTF("Finalize hash with %.*H\n", sizeof(dataBuffer), dataBuffer); - - blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, sizeof(dataBuffer)); + blake256_Update(&btchip_context_D.transactionHashPrefix, + dataBuffer, + sizeof(dataBuffer)); blake256_Final(&btchip_context_D.transactionHashPrefix, hash1); PRINTF("Hash1 %.*H\n", sizeof(hash1), hash1); @@ -117,25 +115,27 @@ unsigned short btchip_apdu_hash_sign() { btchip_write_u32_le(dataBuffer, sighashType); // include sighash type PRINTF("Sighash type: %.*H\n", 4, dataBuffer); - blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, 4); + blake256_Update(&btchip_context_D.transactionHashPrefix, dataBuffer, 4); // include prefix_hash PRINTF("Prefix hash: %.*H\n", sizeof(hash1), hash1); - blake256_Update(&btchip_context_D.transactionHashPrefix, hash1, sizeof(hash1)); + blake256_Update(&btchip_context_D.transactionHashPrefix, hash1, sizeof(hash1)); // include witness_hash PRINTF("Witness hash: %.*H\n", sizeof(hash2), hash2); - blake256_Update(&btchip_context_D.transactionHashPrefix, hash2, sizeof(hash2)); + blake256_Update(&btchip_context_D.transactionHashPrefix, hash2, sizeof(hash2)); // final signature hash blake256_Final(&btchip_context_D.transactionHashPrefix, hash2); PRINTF("Hash to sign: %.*H\n", sizeof(hash2), hash2); - // Sign btchip_signverify_finalhash( - &btchip_private_key_D, 1, hash2, sizeof(hash2), - G_io_apdu_buffer, sizeof(G_io_apdu_buffer), - ((N_btchip.bkp.config.options & - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + &btchip_private_key_D, + 1, + hash2, + sizeof(hash2), + G_io_apdu_buffer, + sizeof(G_io_apdu_buffer), + ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; G_io_apdu_buffer[btchip_context_D.outLength++] = sighashType; @@ -147,8 +147,7 @@ unsigned short btchip_apdu_hash_sign() { CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0xF); catch_discardTransaction: - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; } FINALLY { btchip_set_check_internal_structure_integrity(1); diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index a164244..a3390b5 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -21,14 +21,14 @@ #include "ui_transaction.h" #define P1_PREPARE 0x00 -#define P1_SIGN 0x80 -#define P2_LEGACY 0x00 -#define P2_FIRST 0x01 -#define P2_OTHER 0x80 +#define P1_SIGN 0x80 +#define P2_LEGACY 0x00 +#define P2_FIRST 0x01 +#define P2_OTHER 0x80 -#define BITID_NONE 0 +#define BITID_NONE 0 #define BITID_POWERCYCLE 1 -#define BITID_MULTIPLE 2 +#define BITID_MULTIPLE 2 //#define SLIP_13 0x8000000D @@ -88,7 +88,7 @@ unsigned short btchip_apdu_sign_message_internal() { unsigned char messageLength[3]; unsigned char messageLengthSize; explicit_bzero(&btchip_context_D.transactionSummary, - sizeof(btchip_transaction_summary_t)); + sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { PRINTF("Invalid path\n"); sw = BTCHIP_SW_INCORRECT_DATA; @@ -99,9 +99,9 @@ unsigned short btchip_apdu_sign_message_internal() { btchip_context_D.payToAddressVersion; btchip_context_D.transactionSummary.payToScriptHashVersion = btchip_context_D.payToScriptHashVersion; - memmove( - btchip_context_D.transactionSummary.summarydata.keyPath, - G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); + memmove(btchip_context_D.transactionSummary.summarydata.keyPath, + G_io_apdu_buffer + offset, + MAX_BIP32_PATH_LENGTH); offset += (4 * G_io_apdu_buffer[offset]) + 1; if (p2 == P2_LEGACY) { btchip_context_D.transactionSummary.messageLength = @@ -109,12 +109,10 @@ unsigned short btchip_apdu_sign_message_internal() { offset++; } else { btchip_context_D.transactionSummary.messageLength = - (G_io_apdu_buffer[offset] << 8) | - (G_io_apdu_buffer[offset + 1]); + (G_io_apdu_buffer[offset] << 8) | (G_io_apdu_buffer[offset + 1]); offset += 2; } - if (btchip_context_D.transactionSummary.messageLength == - 0) { + if (btchip_context_D.transactionSummary.messageLength == 0) { PRINTF("Null message length\n"); sw = BTCHIP_SW_INCORRECT_DATA; CLOSE_TRY; @@ -122,35 +120,43 @@ unsigned short btchip_apdu_sign_message_internal() { } btchip_context_D.hashedMessageLength = 0; cx_sha256_init(&btchip_context_D.messageHashPrefix); - cx_sha256_init( - &btchip_context_D.messageHashWitness); - chunkLength = - btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH; - cx_hash(&btchip_context_D.messageHashPrefix.header, 0, - &chunkLength, 1, NULL, 0); - cx_hash(&btchip_context_D.messageHashPrefix.header, 0, + cx_sha256_init(&btchip_context_D.messageHashWitness); + chunkLength = btchip_context_D.coinIdLength + SIGNMAGIC_LENGTH; + cx_hash(&btchip_context_D.messageHashPrefix.header, + 0, + &chunkLength, + 1, + NULL, + 0); + cx_hash(&btchip_context_D.messageHashPrefix.header, + 0, btchip_context_D.coinId, - btchip_context_D.coinIdLength, NULL, 0); - cx_hash(&btchip_context_D.messageHashPrefix.header, 0, - (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0); - if (btchip_context_D.transactionSummary.messageLength < - 0xfd) { - messageLength[0] = - btchip_context_D.transactionSummary.messageLength; + btchip_context_D.coinIdLength, + NULL, + 0); + cx_hash(&btchip_context_D.messageHashPrefix.header, + 0, + (unsigned char *) SIGNMAGIC, + SIGNMAGIC_LENGTH, + NULL, + 0); + if (btchip_context_D.transactionSummary.messageLength < 0xfd) { + messageLength[0] = btchip_context_D.transactionSummary.messageLength; messageLengthSize = 1; } else { messageLength[0] = 0xfd; messageLength[1] = - (btchip_context_D.transactionSummary.messageLength & - 0xff); - messageLength[2] = ((btchip_context_D.transactionSummary - .messageLength >> - 8) & - 0xff); + (btchip_context_D.transactionSummary.messageLength & 0xff); + messageLength[2] = + ((btchip_context_D.transactionSummary.messageLength >> 8) & 0xff); messageLengthSize = 3; } - cx_hash(&btchip_context_D.messageHashPrefix.header, 0, - messageLength, messageLengthSize, NULL, 0); + cx_hash(&btchip_context_D.messageHashPrefix.header, + 0, + messageLength, + messageLengthSize, + NULL, + 0); chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); if ((btchip_context_D.hashedMessageLength + chunkLength) > btchip_context_D.transactionSummary.messageLength) { @@ -159,11 +165,18 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.messageHashPrefix.header, 0, - G_io_apdu_buffer + offset, chunkLength, NULL, 0); - cx_hash( - &btchip_context_D.messageHashWitness.header, - 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0); + cx_hash(&btchip_context_D.messageHashPrefix.header, + 0, + G_io_apdu_buffer + offset, + chunkLength, + NULL, + 0); + cx_hash(&btchip_context_D.messageHashWitness.header, + 0, + G_io_apdu_buffer + offset, + chunkLength, + NULL, + 0); btchip_context_D.hashedMessageLength += chunkLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -181,11 +194,18 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.messageHashPrefix.header, 0, - G_io_apdu_buffer + offset, apduLength, NULL, 0); - cx_hash( - &btchip_context_D.messageHashWitness.header, - 0, G_io_apdu_buffer + offset, apduLength, NULL, 0); + cx_hash(&btchip_context_D.messageHashPrefix.header, + 0, + G_io_apdu_buffer + offset, + apduLength, + NULL, + 0); + cx_hash(&btchip_context_D.messageHashWitness.header, + 0, + G_io_apdu_buffer + offset, + apduLength, + NULL, + 0); btchip_context_D.hashedMessageLength += apduLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -205,8 +225,8 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - if (checkBitId(btchip_context_D.transactionSummary.summarydata - .keyPath) != BITID_NONE) { + if (checkBitId(btchip_context_D.transactionSummary.summarydata.keyPath) != + BITID_NONE) { sw = btchip_compute_hash(); } else { btchip_context_D.io_flags |= IO_ASYNCH_REPLY; @@ -219,8 +239,7 @@ unsigned short btchip_apdu_sign_message_internal() { sw = SW_TECHNICAL_DETAILS(0x0F); } discard : { - explicit_bzero(&btchip_context_D.transactionSummary, - sizeof(btchip_transaction_summary_t)); + explicit_bzero(&btchip_context_D.transactionSummary, sizeof(btchip_transaction_summary_t)); } FINALLY { return sw; @@ -243,19 +262,20 @@ unsigned short btchip_compute_hash() { btchip_context_D.outLength = 0; BEGIN_TRY { TRY { - cx_hash(&btchip_context_D.messageHashPrefix.header, CX_LAST, hash, - 0, hash, 32); + cx_hash(&btchip_context_D.messageHashPrefix.header, CX_LAST, hash, 0, hash, 32); cx_sha256_init(&btchip_context_D.messageHashPrefix); - cx_hash(&btchip_context_D.messageHashPrefix.header, CX_LAST, hash, - 32, hash, 32); - btchip_private_derive_keypair( - btchip_context_D.transactionSummary.summarydata.keyPath, 0, - NULL); + cx_hash(&btchip_context_D.messageHashPrefix.header, CX_LAST, hash, 32, hash, 32); + btchip_private_derive_keypair(btchip_context_D.transactionSummary.summarydata.keyPath, + 0, + NULL); btchip_signverify_finalhash( - &btchip_private_key_D, 1, hash, sizeof(hash), // IN - G_io_apdu_buffer, 100, // OUT - ((N_btchip.bkp.config.options & - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + &btchip_private_key_D, + 1, + hash, + sizeof(hash), // IN + G_io_apdu_buffer, + 100, // OUT + ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; } CATCH_ALL { @@ -263,7 +283,7 @@ unsigned short btchip_compute_hash() { } FINALLY { explicit_bzero(&btchip_context_D.transactionSummary, - sizeof(btchip_transaction_summary_t)); + sizeof(btchip_transaction_summary_t)); } } END_TRY; diff --git a/src/btchip_bagl_extensions.h b/src/btchip_bagl_extensions.h index 1bdb83b..2ba9ea3 100644 --- a/src/btchip_bagl_extensions.h +++ b/src/btchip_bagl_extensions.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #ifndef _BTCHIP_BAGL_H_ #define _BTCHIP_BAGL_H_ diff --git a/src/btchip_base58.c b/src/btchip_base58.c index a93145d..5c4128c 100644 --- a/src/btchip_base58.c +++ b/src/btchip_base58.c @@ -1,134 +1,135 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #define MAX_DEC_INPUT_SIZE 164 #define MAX_ENC_INPUT_SIZE 120 -int btchip_decode_base58(const char *in, size_t length, - unsigned char *out, size_t *outlen) { - unsigned char tmp[MAX_DEC_INPUT_SIZE]; - unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; - unsigned char i; - unsigned char j; - unsigned char startAt; - unsigned char zeroCount = 0; - if (length > MAX_DEC_INPUT_SIZE) { - return -1; - } - memmove(tmp, in, length); - PRINTF("To decode\n%.*H\n",length,tmp); - for (i = 0; i < length; i++) { - if (in[i] >= sizeof(BASE58TABLE)) { - return -1; +int btchip_decode_base58(const char *in, size_t length, unsigned char *out, size_t *outlen) { + unsigned char tmp[MAX_DEC_INPUT_SIZE]; + unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; + unsigned char i; + unsigned char j; + unsigned char startAt; + unsigned char zeroCount = 0; + if (length > MAX_DEC_INPUT_SIZE) { + return -1; } - tmp[i] = BASE58TABLE[(int)in[i]]; - if (tmp[i] == 0xff) { - return -1; + memmove(tmp, in, length); + PRINTF("To decode\n%.*H\n", length, tmp); + for (i = 0; i < length; i++) { + if (in[i] >= sizeof(BASE58TABLE)) { + return -1; + } + tmp[i] = BASE58TABLE[(int) in[i]]; + if (tmp[i] == 0xff) { + return -1; + } } - } - while ((zeroCount < length) && (tmp[zeroCount] == 0)) { - ++zeroCount; - } - j = length; - startAt = zeroCount; - while (startAt < length) { - unsigned short remainder = 0; - unsigned char divLoop; - for (divLoop = startAt; divLoop < length; divLoop++) { - unsigned short digit256 = (unsigned short)(tmp[divLoop] & 0xff); - unsigned short tmpDiv = remainder * 58 + digit256; - tmp[divLoop] = (unsigned char)(tmpDiv / 256); - remainder = (tmpDiv % 256); + while ((zeroCount < length) && (tmp[zeroCount] == 0)) { + ++zeroCount; } - if (tmp[startAt] == 0) { - ++startAt; + j = length; + startAt = zeroCount; + while (startAt < length) { + unsigned short remainder = 0; + unsigned char divLoop; + for (divLoop = startAt; divLoop < length; divLoop++) { + unsigned short digit256 = (unsigned short) (tmp[divLoop] & 0xff); + unsigned short tmpDiv = remainder * 58 + digit256; + tmp[divLoop] = (unsigned char) (tmpDiv / 256); + remainder = (tmpDiv % 256); + } + if (tmp[startAt] == 0) { + ++startAt; + } + buffer[--j] = (unsigned char) remainder; + } + while ((j < length) && (buffer[j] == 0)) { + ++j; + } + length = length - (j - zeroCount); + if (*outlen < length) { + PRINTF("Decode overflow %d %d\n", length, *outlen); + return -1; } - buffer[--j] = (unsigned char)remainder; - } - while ((j < length) && (buffer[j] == 0)) { - ++j; - } - length = length - (j - zeroCount); - if (*outlen < length) { - PRINTF("Decode overflow %d %d\n", length, *outlen); - return -1; - } - memmove(out, buffer + j - zeroCount, length); - PRINTF("Decoded\n%.*H\n",length,out); - *outlen = length; - return 0; + memmove(out, buffer + j - zeroCount, length); + PRINTF("Decoded\n%.*H\n", length, out); + *outlen = length; + return 0; } -int btchip_encode_base58(const unsigned char *in, size_t length, - unsigned char *out, size_t *outlen) { - unsigned char buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; - size_t i = 0, j; - size_t startAt, stopAt; - size_t zeroCount = 0; - size_t outputSize; +int btchip_encode_base58(const unsigned char *in, + size_t length, + unsigned char *out, + size_t *outlen) { + unsigned char buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; + size_t i = 0, j; + size_t startAt, stopAt; + size_t zeroCount = 0; + size_t outputSize; - if (length > MAX_ENC_INPUT_SIZE) { - return -1; - } + if (length > MAX_ENC_INPUT_SIZE) { + return -1; + } - PRINTF("Length to encode %d\n", length); - PRINTF("To encode\n%.*H\n",length,in); + PRINTF("Length to encode %d\n", length); + PRINTF("To encode\n%.*H\n", length, in); - while ((zeroCount < length) && (in[zeroCount] == 0)) { - ++zeroCount; - } + while ((zeroCount < length) && (in[zeroCount] == 0)) { + ++zeroCount; + } - outputSize = (length - zeroCount) * 138 / 100 + 1; - stopAt = outputSize - 1; - for (startAt = zeroCount; startAt < length; startAt++) { - int carry = in[startAt]; - for (j = outputSize - 1; (int)j >= 0; j--) { - carry += 256 * buffer[j]; - buffer[j] = carry % 58; - carry /= 58; + outputSize = (length - zeroCount) * 138 / 100 + 1; + stopAt = outputSize - 1; + for (startAt = zeroCount; startAt < length; startAt++) { + int carry = in[startAt]; + for (j = outputSize - 1; (int) j >= 0; j--) { + carry += 256 * buffer[j]; + buffer[j] = carry % 58; + carry /= 58; - if (j <= stopAt - 1 && carry == 0) { - break; - } + if (j <= stopAt - 1 && carry == 0) { + break; + } + } + stopAt = j; } - stopAt = j; - } - j = 0; - while (j < outputSize && buffer[j] == 0) { - j += 1; - } + j = 0; + while (j < outputSize && buffer[j] == 0) { + j += 1; + } - if (*outlen < zeroCount + outputSize - j) { - *outlen = zeroCount + outputSize - j; - return -1; - } + if (*outlen < zeroCount + outputSize - j) { + *outlen = zeroCount + outputSize - j; + return -1; + } - memset(out, BASE58ALPHABET[0], zeroCount); + memset(out, BASE58ALPHABET[0], zeroCount); - i = zeroCount; - while (j < outputSize) { - out[i++] = BASE58ALPHABET[buffer[j++]]; - } - *outlen = i; - PRINTF("Length encoded %d\n", i); - PRINTF("Encoded\n%.*H\n",i,out); - return 0; + i = zeroCount; + while (j < outputSize) { + out[i++] = BASE58ALPHABET[buffer[j++]]; + } + *outlen = i; + PRINTF("Length encoded %d\n", i); + PRINTF("Encoded\n%.*H\n", i, out); + return 0; } diff --git a/src/btchip_context.c b/src/btchip_context.c index 2c73821..bbd07a6 100644 --- a/src/btchip_context.c +++ b/src/btchip_context.c @@ -1,36 +1,36 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" -void autosetup(void){ +void autosetup(void) { btchip_config_t config; unsigned char i; unsigned char tmp[32]; explicit_bzero(&config, sizeof(btchip_config_t)); config.options |= BTCHIP_OPTION_DETERMINISTIC_SIGNATURE; - config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when - // supporting multi output + config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when + // supporting multi output - nvm_write((void *)&N_btchip.bkp.config, &config, sizeof(config)); + nvm_write((void *) &N_btchip.bkp.config, &config, sizeof(config)); cx_rng(tmp, sizeof(tmp)); - nvm_write((void *)&N_btchip.bkp.trustedinput_key, tmp, sizeof(tmp)); + nvm_write((void *) &N_btchip.bkp.trustedinput_key, tmp, sizeof(tmp)); i = 1; - nvm_write((void *)&N_btchip.config_valid, &i, 1); + nvm_write((void *) &N_btchip.config_valid, &i, 1); } /** @@ -42,11 +42,9 @@ void btchip_context_init() { SB_SET(btchip_context_D.halted, 0); btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - explicit_bzero(btchip_context_D.totalOutputAmount, - sizeof(btchip_context_D.totalOutputAmount)); + explicit_bzero(btchip_context_D.totalOutputAmount, sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; - if (N_btchip.config_valid != 0x01) { autosetup(); } @@ -56,24 +54,21 @@ void btchip_context_init() { PRINTF("No configuration found\n"); defaultMode = BTCHIP_MODE_WALLET; - } - else { + } else { btchip_context_D.payToAddressVersion = G_coin_config->p2pkh_version; btchip_context_D.payToScriptHashVersion = G_coin_config->p2sh_version; btchip_context_D.coinFamily = G_coin_config->family; btchip_context_D.coinIdLength = strlen(PIC(G_coin_config->coinid)); - memmove(btchip_context_D.coinId, PIC(G_coin_config->coinid), - btchip_context_D.coinIdLength); - btchip_context_D.shortCoinIdLength = - strlen(PIC(G_coin_config->name_short)); - memmove(btchip_context_D.shortCoinId, PIC(G_coin_config->name_short), - btchip_context_D.shortCoinIdLength); - + memmove(btchip_context_D.coinId, PIC(G_coin_config->coinid), btchip_context_D.coinIdLength); + btchip_context_D.shortCoinIdLength = strlen(PIC(G_coin_config->name_short)); + memmove(btchip_context_D.shortCoinId, + PIC(G_coin_config->name_short), + btchip_context_D.shortCoinIdLength); } if (!N_btchip.storageInitialized) { - unsigned char initialized = 1, denied=1; + unsigned char initialized = 1, denied = 1; - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &denied, 1); - nvm_write((void *)&N_btchip.storageInitialized, &initialized, 1); + nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &denied, 1); + nvm_write((void *) &N_btchip.storageInitialized, &initialized, 1); } } diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index d6f4f9b..da3051a 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -1,43 +1,46 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "blake256.h" const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { - 0x19, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG + 0x19, + 0x76, + 0xA9, + 0x14}; // script length, OP_DUP, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = {0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL + 0x17, + 0xA9, + 0x14}; // script length, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; unsigned char btchip_output_script_is_regular(unsigned char *buffer) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == + 0) && (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { + TRANSACTION_OUTPUT_SCRIPT_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { return 1; } PRINTF("Irregular script: %.*H\n", 10, buffer); @@ -45,11 +48,12 @@ unsigned char btchip_output_script_is_regular(unsigned char *buffer) { } unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + if ((memcmp(buffer, + TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { return 1; } return 0; @@ -60,15 +64,13 @@ unsigned char btchip_output_script_is_op_return(unsigned char *buffer) { } unsigned char btchip_output_script_is_op_create(unsigned char *buffer) { - return (!btchip_output_script_is_regular(buffer) && - !btchip_output_script_is_p2sh(buffer) && + return (!btchip_output_script_is_regular(buffer) && !btchip_output_script_is_p2sh(buffer) && !btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && (buffer[buffer[0]] == 0xC1)); } unsigned char btchip_output_script_is_op_call(unsigned char *buffer) { - return (!btchip_output_script_is_regular(buffer) && - !btchip_output_script_is_p2sh(buffer) && + return (!btchip_output_script_is_regular(buffer) && !btchip_output_script_is_p2sh(buffer) && !btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && (buffer[buffer[0]] == 0xC2)); } @@ -82,12 +84,10 @@ unsigned char btchip_rng_u8_modulo(unsigned char modulo) { return (candidate % modulo); } -unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, - unsigned short length) { +unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, unsigned short length) { unsigned char error = 0; while (length--) { - error |= ((unsigned char *)buf1)[length] ^ - ((unsigned char *)buf2)[length]; + error |= ((unsigned char *) buf1)[length] ^ ((unsigned char *) buf2)[length]; } if (length != 0xffff) { return 1; @@ -95,17 +95,16 @@ unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, return error; } -unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, - unsigned char skipSign) { +unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, unsigned char skipSign) { unsigned char i; unsigned long int result = 0; unsigned char shiftValue = (be ? 24 : 0); for (i = 0; i < 4; i++) { - unsigned char x = (unsigned char)buffer[i]; + unsigned char x = (unsigned char) buffer[i]; if ((i == 0) && skipSign) { x &= 0x7f; } - result += ((unsigned long int)x) << shiftValue; + result += ((unsigned long int) x) << shiftValue; if (be) { shiftValue -= 8; } else { @@ -129,18 +128,15 @@ void btchip_write_u32_le(unsigned char *buffer, unsigned long int value) { buffer[3] = ((value >> 24) & 0xff); } -void btchip_retrieve_keypair_discard(unsigned char *privateComponent, - unsigned char derivePublic) { +void btchip_retrieve_keypair_discard(unsigned char *privateComponent, unsigned char derivePublic) { BEGIN_TRY { TRY { - cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, - &btchip_private_key_D); + cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, &btchip_private_key_D); - PRINTF("Using private component\n%.*H\n",32,privateComponent); + PRINTF("Using private component\n%.*H\n", 32, privateComponent); if (derivePublic) { - cx_ecfp_generate_pair(BTCHIP_CURVE, &btchip_public_key_D, - &btchip_private_key_D, 1); + cx_ecfp_generate_pair(BTCHIP_CURVE, &btchip_public_key_D, &btchip_private_key_D, 1); } } FINALLY { @@ -149,8 +145,7 @@ void btchip_retrieve_keypair_discard(unsigned char *privateComponent, END_TRY; } -void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char *out) { +void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out) { union { BLAKE256_CTX blake; cx_ripemd160_t riprip; @@ -164,21 +159,23 @@ void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, cx_hash(&u.riprip.header, CX_LAST, buffer, 32, out, 32); } -unsigned short btchip_public_key_to_encoded_base58( - unsigned char *in, unsigned short inlen, unsigned char *out, - unsigned short outlen, unsigned short version, - unsigned char alreadyHashed) { +unsigned short btchip_public_key_to_encoded_base58(unsigned char *in, + unsigned short inlen, + unsigned char *out, + unsigned short outlen, + unsigned short version, + unsigned char alreadyHashed) { unsigned char tmpBuffer[26]; unsigned char checksumBuffer[32]; - //cx_blake2b_t hash; + // cx_blake2b_t hash; BLAKE256_CTX hash; unsigned char versionSize = (version > 255 ? 2 : 1); size_t outputLen; if (!alreadyHashed) { - PRINTF("To hash\n%.*H\n",inlen,in); + PRINTF("To hash\n%.*H\n", inlen, in); btchip_public_key_hash160(in, inlen, tmpBuffer + versionSize); - PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); + PRINTF("Hash160\n%.*H\n", 20, (tmpBuffer + versionSize)); if (version > 255) { tmpBuffer[0] = (version >> 8); tmpBuffer[1] = version; @@ -196,7 +193,7 @@ unsigned short btchip_public_key_to_encoded_base58( blake256_Update(&hash, checksumBuffer, 32); blake256_Final(&hash, checksumBuffer); - PRINTF("Checksum\n%.*H\n",4,checksumBuffer); + PRINTF("Checksum\n%.*H\n", 4, checksumBuffer); memmove(tmpBuffer + 20 + versionSize, checksumBuffer, 4); outputLen = outlen; @@ -206,8 +203,7 @@ unsigned short btchip_public_key_to_encoded_base58( return outputLen; } -void btchip_swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size) { +void btchip_swap_bytes(unsigned char *target, unsigned char *source, unsigned char size) { unsigned char i; for (i = 0; i < size; i++) { target[i] = source[size - 1 - i]; @@ -221,7 +217,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, unsigned char hashBuffer[32]; cx_sha256_t hash; size_t outputLen = outlen; - if (btchip_decode_base58((char *)in, inlen, out, &outputLen) < 0) { + if (btchip_decode_base58((char *) in, inlen, out, &outputLen) < 0) { THROW(EXCEPTION); } outlen = outputLen; @@ -233,7 +229,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, cx_hash(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer, 32); if (memcmp(out + outlen - 4, hashBuffer, 4)) { - PRINTF("Hash checksum mismatch\n%.*H\n",sizeof(hashBuffer),hashBuffer); + PRINTF("Hash checksum mismatch\n%.*H\n", sizeof(hashBuffer), hashBuffer); THROW(INVALID_CHECKSUM); } @@ -257,8 +253,11 @@ void btchip_private_derive_keypair(unsigned char *bip32Path, bip32PathInt[i] = btchip_read_u32(bip32Path, 1, 0); bip32Path += 4; } - os_perso_derive_node_bip32(CX_CURVE_256K1, bip32PathInt, bip32PathLength, - privateComponent, out_chainCode); + os_perso_derive_node_bip32(CX_CURVE_256K1, + bip32PathInt, + bip32PathLength, + privateComponent, + out_chainCode); btchip_retrieve_keypair_discard(privateComponent, derivePublic); explicit_bzero(privateComponent, sizeof(privateComponent)); } @@ -268,7 +267,6 @@ Checks if the values of a derivation path are within "normal" (arbitrary) ranges Account < 100, change == 1 or 0, address index < 50000 Returns 1 if the path is unusual, or not compliant with BIP44*/ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path) { - unsigned char i, path_len; unsigned int bip32PathInt[MAX_BIP32_PATH]; @@ -283,18 +281,19 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa bip32Path += 4; } - // If the path length is not compliant with BIP44 or if the purpose/coin type don't match regular usage - if(path_len != BIP44_PATH_LEN || - ((bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { + // If the path length is not compliant with BIP44 or if the purpose/coin type don't match + // regular usage + if (path_len != BIP44_PATH_LEN || ((bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 44 && + (bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 49 && + (bip32PathInt[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 84)) { return 1; } // If the account or address index is very high or if the change isn't 1, return a warning - if((bip32PathInt[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || - bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + if ((bip32PathInt[BIP44_ACCOUNT_OFFSET] ^ 0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || + bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path + ? 1 + : 0 || bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { return 1; } @@ -302,8 +301,7 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa } // Print a BIP32 path as an ascii string to display on the device screen -unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len) { - +unsigned char bip32_print_path(unsigned char *bip32Path, char *out, unsigned char max_out_len) { unsigned char bip32PathLength; unsigned char i, offset; unsigned int current_level; @@ -315,66 +313,79 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned cha } bip32Path++; out[0] = ' '; - offset=1; + offset = 1; for (i = 0; i < bip32PathLength; i++) { current_level = btchip_read_u32(bip32Path, 1, 0); - hardened = (bool)(current_level & 0x80000000); - if(hardened) { - //remove hardening flag + hardened = (bool) (current_level & 0x80000000); + if (hardened) { + // remove hardening flag current_level ^= 0x80000000; } bip32Path += 4; - snprintf(out+offset, max_out_len-offset, "%u", current_level); + snprintf(out + offset, max_out_len - offset, "%u", current_level); offset = strnlen(out, max_out_len); - if(offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); - if(hardened) out[offset++] = '\''; + if (offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); + if (hardened) out[offset++] = '\''; out[offset++] = '/'; out[offset] = '\0'; } // remove last '/' - out[offset-1] = '\0'; + out[offset - 1] = '\0'; - return offset -1; + return offset - 1; } void btchip_transaction_add_output(unsigned char *hash160Address, - unsigned char *amount, unsigned char p2sh) { - const unsigned char *pre = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE - : TRANSACTION_OUTPUT_SCRIPT_PRE); - const unsigned char *post = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST - : TRANSACTION_OUTPUT_SCRIPT_POST); - unsigned char sizePre = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) - : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); + unsigned char *amount, + unsigned char p2sh) { + const unsigned char *pre = + (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE : TRANSACTION_OUTPUT_SCRIPT_PRE); + const unsigned char *post = + (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST : TRANSACTION_OUTPUT_SCRIPT_POST); + unsigned char sizePre = + (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); unsigned char sizePost = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST) : sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)); if (amount != NULL) { btchip_swap_bytes(btchip_context_D.tmp, amount, 8); btchip_context_D.tmp += 8; } - memmove(btchip_context_D.tmp, (void *)pre, sizePre); + memmove(btchip_context_D.tmp, (void *) pre, sizePre); btchip_context_D.tmp += sizePre; memmove(btchip_context_D.tmp, hash160Address, 20); btchip_context_D.tmp += 20; - memmove(btchip_context_D.tmp, (void *)post, sizePost); + memmove(btchip_context_D.tmp, (void *) post, sizePost); btchip_context_D.tmp += sizePost; } - -void btchip_signverify_finalhash(void *keyContext, unsigned char sign, - unsigned char *in, unsigned short inlen, - unsigned char *out, unsigned short outlen, +void btchip_signverify_finalhash(void *keyContext, + unsigned char sign, + unsigned char *in, + unsigned short inlen, + unsigned char *out, + unsigned short outlen, unsigned char rfc6979) { if (sign) { unsigned int info = 0; - cx_ecdsa_sign((cx_ecfp_private_key_t *)keyContext, + cx_ecdsa_sign((cx_ecfp_private_key_t *) keyContext, CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), - CX_SHA256, in, inlen, out, outlen, &info); + CX_SHA256, + in, + inlen, + out, + outlen, + &info); if (info & CX_ECCINFO_PARITY_ODD) { out[0] |= 0x01; } } else { - cx_ecdsa_verify((cx_ecfp_public_key_t *)keyContext, CX_LAST, - CX_SHA256, in, inlen, out, outlen); + cx_ecdsa_verify((cx_ecfp_public_key_t *) keyContext, + CX_LAST, + CX_SHA256, + in, + inlen, + out, + outlen); } } diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 74d1723..c3bdd59 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "btchip_internal.h" #include "btchip_apdu_constants.h" @@ -25,18 +25,18 @@ void check_transaction_available(unsigned char x) { if (btchip_context_D.transactionDataRemaining < x) { - PRINTF("Check transaction available failed %d < %d\n", btchip_context_D.transactionDataRemaining, x); + PRINTF("Check transaction available failed %d < %d\n", + btchip_context_D.transactionDataRemaining, + x); THROW(EXCEPTION); } } -#define OP_HASH160 0xA9 -#define OP_EQUAL 0x87 +#define OP_HASH160 0xA9 +#define OP_EQUAL 0x87 #define OP_CHECKMULTISIG 0xAE -unsigned char transaction_amount_add_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { +unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, unsigned char *b) { unsigned char carry = 0; unsigned char i; for (i = 0; i < 8; i++) { @@ -47,9 +47,7 @@ unsigned char transaction_amount_add_be(unsigned char *target, return carry; } -unsigned char transaction_amount_sub_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { +unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b) { unsigned char borrow = 0; unsigned char i; for (i = 0; i < 8; i++) { @@ -67,7 +65,7 @@ unsigned char transaction_amount_sub_be(unsigned char *target, borrow = 1; tmpA += 255 + 1; } - target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); + target[8 - 1 - i] = (unsigned char) (tmpA - tmpB); } return borrow; @@ -75,13 +73,19 @@ unsigned char transaction_amount_sub_be(unsigned char *target, void transaction_offset(unsigned char value) { if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { - PRINTF("Add to prefix hash: ", value ,btchip_context_D.transactionBufferPointer); - blake256_Update(&btchip_context_D.transactionHashPrefix, btchip_context_D.transactionBufferPointer, value); - blake256_Update(&btchip_context_D.transactionHashAuthorization, btchip_context_D.transactionBufferPointer, value); + PRINTF("Add to prefix hash: ", value, btchip_context_D.transactionBufferPointer); + blake256_Update(&btchip_context_D.transactionHashPrefix, + btchip_context_D.transactionBufferPointer, + value); + blake256_Update(&btchip_context_D.transactionHashAuthorization, + btchip_context_D.transactionBufferPointer, + value); } if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_WITNESS) != 0) { PRINTF("Add to witness hash: ", value, btchip_context_D.transactionBufferPointer); - blake256_Update(&btchip_context_D.transactionHashWitness, btchip_context_D.transactionBufferPointer, value); + blake256_Update(&btchip_context_D.transactionHashWitness, + btchip_context_D.transactionBufferPointer, + value); } } @@ -102,19 +106,15 @@ unsigned long int transaction_get_varint(void) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(2); - result = - (unsigned long int)(*btchip_context_D.transactionBufferPointer) | - ((unsigned long int)(*(btchip_context_D.transactionBufferPointer + - 1)) - << 8); + result = (unsigned long int) (*btchip_context_D.transactionBufferPointer) | + ((unsigned long int) (*(btchip_context_D.transactionBufferPointer + 1)) << 8); transaction_offset_increase(2); return result; } else if (firstByte == 0xFE) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(4); - result = - btchip_read_u32(btchip_context_D.transactionBufferPointer, 0, 0); + result = btchip_read_u32(btchip_context_D.transactionBufferPointer, 0, 0); transaction_offset_increase(4); return result; } else { @@ -131,497 +131,465 @@ void transaction_parse(unsigned char parseMode) { BEGIN_TRY { TRY { for (;;) { - PRINTF("TX parse, state=%d\n", btchip_context_D.transactionContext.transactionState); + PRINTF("TX parse, state=%d\n", + btchip_context_D.transactionContext.transactionState); switch (btchip_context_D.transactionContext.transactionState) { - case BTCHIP_TRANSACTION_NONE: { - PRINTF("Init transaction parser\n"); - // Reset transaction state - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs = 0; - btchip_context_D.transactionContext - .transactionCurrentInputOutput = 0; - btchip_context_D.transactionContext.scriptRemaining = 0; - explicit_bzero( - btchip_context_D.transactionContext.transactionAmount, - sizeof(btchip_context_D.transactionContext - .transactionAmount)); - // TODO : transactionControlFid - // Reset hashes - blake256_Init(&btchip_context_D.transactionHashPrefix); - blake256_Init(&btchip_context_D.transactionHashWitness); - blake256_Init(&btchip_context_D.transactionHashAuthorization); - //cx_blake2b_init(&btchip_context_D.transactionHashPrefix, 256); - //cx_blake2b_init(&btchip_context_D.transactionHashWitness, 256); - - - // Parse the beginning of the transaction - // Version - check_transaction_available(4); - memmove(btchip_context_D.transactionVersion, - btchip_context_D.transactionBufferPointer, 4); - // decred "no witness" serialization type ORing - btchip_context_D.transactionBufferPointer[2] |= 1; - btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; // prefix only - transaction_offset_increase(4); - - btchip_context_D.transactionBufferPointer -= 4; - btchip_context_D.transactionDataRemaining += 4; - btchip_context_D.transactionBufferPointer[2] |= 3; - btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; // witness only - transaction_offset_increase(4); - - btchip_context_D.transactionHashOption = 0x05; // both prefix and witness hash - - - // Number of inputs - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs = - transaction_get_varint(); - btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; - - // Ready to proceed - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - - // no break is intentional - __attribute__((fallthrough)); - } + case BTCHIP_TRANSACTION_NONE: { + PRINTF("Init transaction parser\n"); + // Reset transaction state + btchip_context_D.transactionContext.transactionRemainingInputsOutputs = 0; + btchip_context_D.transactionContext.transactionCurrentInputOutput = 0; + btchip_context_D.transactionContext.scriptRemaining = 0; + explicit_bzero( + btchip_context_D.transactionContext.transactionAmount, + sizeof(btchip_context_D.transactionContext.transactionAmount)); + // TODO : transactionControlFid + // Reset hashes + blake256_Init(&btchip_context_D.transactionHashPrefix); + blake256_Init(&btchip_context_D.transactionHashWitness); + blake256_Init(&btchip_context_D.transactionHashAuthorization); + // cx_blake2b_init(&btchip_context_D.transactionHashPrefix, 256); + // cx_blake2b_init(&btchip_context_D.transactionHashWitness, 256); + + // Parse the beginning of the transaction + // Version + check_transaction_available(4); + memmove(btchip_context_D.transactionVersion, + btchip_context_D.transactionBufferPointer, + 4); + // decred "no witness" serialization type ORing + btchip_context_D.transactionBufferPointer[2] |= 1; + btchip_context_D.transactionHashOption = + TRANSACTION_HASH_FULL; // prefix only + transaction_offset_increase(4); - case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { - unsigned char trustedInputFlag = 1; - PRINTF("Process input\n"); - if (btchip_context_D.transactionContext - .transactionRemainingInputsOutputs == 0) { - // No more inputs to hash, move forward + btchip_context_D.transactionBufferPointer -= 4; + btchip_context_D.transactionDataRemaining += 4; + btchip_context_D.transactionBufferPointer[2] |= 3; + btchip_context_D.transactionHashOption = + TRANSACTION_HASH_WITNESS; // witness only + transaction_offset_increase(4); + + btchip_context_D.transactionHashOption = + 0x05; // both prefix and witness hash + + // Number of inputs + btchip_context_D.transactionContext.transactionRemainingInputsOutputs = + transaction_get_varint(); + btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; + + // Ready to proceed btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_DONE; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - PRINTF("Waiting for more data...\n"); - goto ok; - } - // Proceed with the next input - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - PRINTF("PARSE_MODE_TRUSTED_INPUT\n"); - check_transaction_available( - 37); // prevout : 32 hash + 4 index + 1 tree - transaction_offset_increase(37); + BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + + // no break is intentional + __attribute__((fallthrough)); } - if (parseMode == PARSE_MODE_SIGNATURE) { - PRINTF("PARSE_MODE_SIGNATURE\n"); - unsigned char trustedInputLength; - unsigned char trustedInput[0x38]; - unsigned char amount[8]; - unsigned char *savePointer; - - // Expect the trusted input flag and trusted input - // length - check_transaction_available(2); - switch (*btchip_context_D.transactionBufferPointer) { - case 0: - trustedInputFlag = 0; - break; - case 1: - trustedInputFlag = 1; - break; - - default: - PRINTF("Invalid trusted input flag\n"); - goto fail; + + case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { + unsigned char trustedInputFlag = 1; + PRINTF("Process input\n"); + if (btchip_context_D.transactionContext.transactionRemainingInputsOutputs == + 0) { + // No more inputs to hash, move forward + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_INPUT_HASHING_DONE; + continue; } - /* - trustedInputLength = - *(btchip_context_D.transactionBufferPointer + 1); - if (trustedInputLength > sizeof(trustedInput)) { - PRINTF("Trusted input too long\n"); - goto fail; + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + PRINTF("Waiting for more data...\n"); + goto ok; } - */ - - if (!trustedInputFlag) { - - if (!optionP2SHSkip2FA) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - - btchip_context_D.transactionBufferPointer++; - btchip_context_D.transactionDataRemaining--; + // Proceed with the next input + if (parseMode == PARSE_MODE_TRUSTED_INPUT) { + PRINTF("PARSE_MODE_TRUSTED_INPUT\n"); check_transaction_available( - 36); // prevout : 32 hash + 4 index - transaction_offset_increase(36); - PRINTF("Marking relaxed input\n"); - btchip_context_D.transactionContext.relaxed = 1; - /* - PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; - */ - } else { - trustedInputLength = *( - btchip_context_D.transactionBufferPointer + 1); - if ((trustedInputLength > sizeof(trustedInput)) || - (trustedInputLength < 8)) { - PRINTF("Invalid trusted input size\n"); - goto fail; - } - - check_transaction_available(2 + trustedInputLength); - cx_hmac_sha256( - (const uint8_t *) N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), - btchip_context_D.transactionBufferPointer + 2, - trustedInputLength - 8, trustedInput, trustedInputLength); - if (btchip_secure_memcmp( - trustedInput, - btchip_context_D.transactionBufferPointer + - 2 + trustedInputLength - 8, - 8) != 0) { - PRINTF("Invalid signature\n"); - goto fail; - } - memmove( - trustedInput, - btchip_context_D.transactionBufferPointer + 2, - trustedInputLength - 8); - if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { - PRINTF("Failed to verify trusted input signature\n"); - goto fail; - } - else { - PRINTF("Good Signature\n"); + 37); // prevout : 32 hash + 4 index + 1 tree + transaction_offset_increase(37); + } + if (parseMode == PARSE_MODE_SIGNATURE) { + PRINTF("PARSE_MODE_SIGNATURE\n"); + unsigned char trustedInputLength; + unsigned char trustedInput[0x38]; + unsigned char amount[8]; + unsigned char *savePointer; + + // Expect the trusted input flag and trusted input + // length + check_transaction_available(2); + switch (*btchip_context_D.transactionBufferPointer) { + case 0: + trustedInputFlag = 0; + break; + case 1: + trustedInputFlag = 1; + break; + + default: + PRINTF("Invalid trusted input flag\n"); + goto fail; } - - // Update the hash with prevout data - savePointer = - btchip_context_D.transactionBufferPointer; //trusted input 01 /* - // Check if a P2SH script is used - if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == - 0) { - PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = - 0; + trustedInputLength = + *(btchip_context_D.transactionBufferPointer + 1); + if (trustedInputLength > sizeof(trustedInput)) { + PRINTF("Trusted input too long\n"); + goto fail; } */ - btchip_context_D.transactionBufferPointer = - trustedInput + 4; - PRINTF("Trusted input hash\n%.*H\n",36,btchip_context_D.transactionBufferPointer); - transaction_offset(36); - - btchip_context_D.transactionBufferPointer = - savePointer + (2 + trustedInputLength); - btchip_context_D.transactionDataRemaining -= - (2 + trustedInputLength); - - // add Decred tree - check_transaction_available(1); - transaction_offset_increase(1); - // Update the amount - - btchip_swap_bytes(amount, trustedInput + 40, 8); - if (transaction_amount_add_be( - btchip_context_D.transactionContext - .transactionAmount, - btchip_context_D.transactionContext - .transactionAmount, - amount)) { - PRINTF("Overflow\n"); - goto fail; + if (!trustedInputFlag) { + if (!optionP2SHSkip2FA) { + PRINTF("Untrusted input not authorized\n"); + goto fail; + } + + btchip_context_D.transactionBufferPointer++; + btchip_context_D.transactionDataRemaining--; + check_transaction_available(36); // prevout : 32 hash + 4 index + transaction_offset_increase(36); + PRINTF("Marking relaxed input\n"); + btchip_context_D.transactionContext.relaxed = 1; + /* + PRINTF("Clearing P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 0; + */ + } else { + trustedInputLength = + *(btchip_context_D.transactionBufferPointer + 1); + if ((trustedInputLength > sizeof(trustedInput)) || + (trustedInputLength < 8)) { + PRINTF("Invalid trusted input size\n"); + goto fail; + } + + check_transaction_available(2 + trustedInputLength); + cx_hmac_sha256((const uint8_t *) N_btchip.bkp.trustedinput_key, + sizeof(N_btchip.bkp.trustedinput_key), + btchip_context_D.transactionBufferPointer + 2, + trustedInputLength - 8, + trustedInput, + trustedInputLength); + if (btchip_secure_memcmp(trustedInput, + btchip_context_D.transactionBufferPointer + + 2 + trustedInputLength - 8, + 8) != 0) { + PRINTF("Invalid signature\n"); + goto fail; + } + memmove(trustedInput, + btchip_context_D.transactionBufferPointer + 2, + trustedInputLength - 8); + if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { + PRINTF("Failed to verify trusted input signature\n"); + goto fail; + } else { + PRINTF("Good Signature\n"); + } + + // Update the hash with prevout data + savePointer = + btchip_context_D.transactionBufferPointer; // trusted input 01 + /* + // Check if a P2SH script is used + if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == + 0) { + PRINTF("Clearing P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = + 0; + } + */ + btchip_context_D.transactionBufferPointer = trustedInput + 4; + PRINTF("Trusted input hash\n%.*H\n", + 36, + btchip_context_D.transactionBufferPointer); + transaction_offset(36); + + btchip_context_D.transactionBufferPointer = + savePointer + (2 + trustedInputLength); + btchip_context_D.transactionDataRemaining -= + (2 + trustedInputLength); + + // add Decred tree + check_transaction_available(1); + transaction_offset_increase(1); + + // Update the amount + + btchip_swap_bytes(amount, trustedInput + 40, 8); + if (transaction_amount_add_be( + btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.transactionContext.transactionAmount, + amount)) { + PRINTF("Overflow\n"); + goto fail; + } + + PRINTF("Adding amount\n%.*H\n", 8, (trustedInput + 40)); + PRINTF("New amount\n%.*H\n", + 8, + btchip_context_D.transactionContext.transactionAmount); } - - PRINTF("Adding amount\n%.*H\n",8,(trustedInput + 40)); - PRINTF("New amount\n%.*H\n",8,btchip_context_D.transactionContext.transactionAmount); } + // DIRTY: include utxo script len and script in witness hash + btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; - - } - // DIRTY: include utxo script len and script in witness hash - btchip_context_D.transactionHashOption = TRANSACTION_HASH_WITNESS; - - // Read the script length - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - - if ((parseMode == PARSE_MODE_SIGNATURE) && - !trustedInputFlag) { - // Only proceeds if this is not to be signed - so length - // should be null - if (btchip_context_D.transactionContext - .scriptRemaining != 0) { - PRINTF("Request to sign relaxed input\n"); - if (!optionP2SHSkip2FA) { - goto fail; + // Read the script length + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); + PRINTF("Script to read " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + + if ((parseMode == PARSE_MODE_SIGNATURE) && !trustedInputFlag) { + // Only proceeds if this is not to be signed - so length + // should be null + if (btchip_context_D.transactionContext.scriptRemaining != 0) { + PRINTF("Request to sign relaxed input\n"); + if (!optionP2SHSkip2FA) { + goto fail; + } } } - } - PRINTF("NEXT_STATE\n"); - // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; + PRINTF("NEXT_STATE\n"); + // Move on + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - // no break is intentional - __attribute__((fallthrough)); - } - case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process input script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; + // no break is intentional + __attribute__((fallthrough)); } - // Scan for P2SH consumption - huge shortcut, but fine - // enough - // Also usable in SegWit mode - if (btchip_context_D.transactionContext.scriptRemaining == - 1) { - if (*btchip_context_D.transactionBufferPointer == - OP_CHECKMULTISIG) { - if (optionP2SHSkip2FA) { - PRINTF("Marking P2SH consumption\n"); - btchip_context_D.transactionContext - .consumeP2SH = 1; + case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process input script, remaining " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Scan for P2SH consumption - huge shortcut, but fine + // enough + // Also usable in SegWit mode + if (btchip_context_D.transactionContext.scriptRemaining == 1) { + if (*btchip_context_D.transactionBufferPointer == OP_CHECKMULTISIG) { + if (optionP2SHSkip2FA) { + PRINTF("Marking P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 1; + } + } else { + // When using the P2SH shortcut, all inputs must use + // P2SH + PRINTF("Disabling P2SH consumption\n"); + btchip_context_D.transactionContext.consumeP2SH = 0; } - } else { - // When using the P2SH shortcut, all inputs must use - // P2SH - PRINTF("Disabling P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; + transaction_offset_increase(1); + btchip_context_D.transactionContext.scriptRemaining--; } - transaction_offset_increase(1); - btchip_context_D.transactionContext.scriptRemaining--; - } - if (btchip_context_D.transactionContext.scriptRemaining == - 0) { - // restore full hash - btchip_context_D.transactionHashOption = 0x01; + if (btchip_context_D.transactionContext.scriptRemaining == 0) { + // restore full hash + btchip_context_D.transactionHashOption = 0x01; - if (parseMode == PARSE_MODE_SIGNATURE) { - btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; + if (parseMode == PARSE_MODE_SIGNATURE) { + btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; + } + // Sequence + check_transaction_available(4); + transaction_offset_increase(4); + // Move to next input + btchip_context_D.transactionContext.transactionRemainingInputsOutputs--; + btchip_context_D.transactionContext.transactionCurrentInputOutput++; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + continue; } - // Sequence - check_transaction_available(4); - transaction_offset_increase(4); - // Move to next input - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext - .transactionCurrentInputOutput++; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - continue; - } - // Save the last script byte for the P2SH check - dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext - .scriptRemaining - - 1 - ? btchip_context_D.transactionContext - .scriptRemaining - - 1 - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { - PRINTF("Input hashing done\n"); - if (parseMode == PARSE_MODE_SIGNATURE) { - - btchip_context_D.transactionContext - .transactionState = - BTCHIP_TRANSACTION_PRESIGN_READY; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; + // Save the last script byte for the P2SH check + dataAvailable = + (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext.scriptRemaining - 1 + ? btchip_context_D.transactionContext.scriptRemaining - 1 + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; + break; } - // Number of outputs - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs = - transaction_get_varint(); - btchip_context_D.transactionContext - .transactionCurrentInputOutput = 0; - PRINTF("Number of outputs : " DEBUG_LONG "\n", btchip_context_D.transactionContext .transactionRemainingInputsOutputs); - // Ready to proceed - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - - // no break is intentional - __attribute__((fallthrough)); - } - case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { - if (btchip_context_D.transactionContext - .transactionRemainingInputsOutputs == 0) { - // No more outputs to hash, move forward + case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { + PRINTF("Input hashing done\n"); + if (parseMode == PARSE_MODE_SIGNATURE) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PRESIGN_READY; + continue; + } + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Number of outputs + btchip_context_D.transactionContext.transactionRemainingInputsOutputs = + transaction_get_varint(); + btchip_context_D.transactionContext.transactionCurrentInputOutput = 0; + PRINTF( + "Number of outputs : " DEBUG_LONG "\n", + btchip_context_D.transactionContext.transactionRemainingInputsOutputs); + // Ready to proceed btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; - continue; - } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Amount - check_transaction_available(8); - if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && - (btchip_context_D.transactionContext - .transactionCurrentInputOutput == - btchip_context_D.transactionTargetInput)) { - // Save the amount - memmove(btchip_context_D.transactionContext - .transactionAmount, - btchip_context_D.transactionBufferPointer, - 8); - btchip_context_D.trustedInputProcessed = 1; - PRINTF("Input processed\n"); - } - transaction_offset_increase(8); + BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - // script version - check_transaction_available(2); - transaction_offset_increase(2); + // no break is intentional + __attribute__((fallthrough)); + } + case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { + if (btchip_context_D.transactionContext.transactionRemainingInputsOutputs == + 0) { + // No more outputs to hash, move forward + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; + continue; + } + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Amount + check_transaction_available(8); + if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && + (btchip_context_D.transactionContext.transactionCurrentInputOutput == + btchip_context_D.transactionTargetInput)) { + // Save the amount + memmove(btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.transactionBufferPointer, + 8); + btchip_context_D.trustedInputProcessed = 1; + PRINTF("Input processed\n"); + } + transaction_offset_increase(8); - // Read the script length - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); + // script version + check_transaction_available(2); + transaction_offset_increase(2); - PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; + // Read the script length + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); - // no break is intentional - __attribute__((fallthrough)); - } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process output script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - /* - // Special check if consuming a P2SH script - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - // Assume the full input script is sent in a single APDU, - then do the ghetto validation - if ((btchip_context_D.transactionBufferPointer[0] == - OP_HASH160) && - (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining - - 1] == OP_EQUAL)) { - PRINTF("Marking P2SH output\n"); - btchip_context_D.transactionContext.consumeP2SH = 1; - } - } - */ - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - if (btchip_context_D.transactionContext.scriptRemaining == - 0) { - // Move to next output - btchip_context_D.transactionContext - .transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext - .transactionCurrentInputOutput++; + PRINTF("Script to read " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + // Move on btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - continue; + BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; + + // no break is intentional + __attribute__((fallthrough)); } - dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext - .scriptRemaining - ? btchip_context_D.transactionContext - .scriptRemaining - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; + case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process output script, remaining " DEBUG_LONG "\n", + btchip_context_D.transactionContext.scriptRemaining); + /* + // Special check if consuming a P2SH script + if (parseMode == PARSE_MODE_TRUSTED_INPUT) { + // Assume the full input script is sent in a single APDU, + then do the ghetto validation + if ((btchip_context_D.transactionBufferPointer[0] == + OP_HASH160) && + (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining + - 1] == OP_EQUAL)) { + PRINTF("Marking P2SH output\n"); + btchip_context_D.transactionContext.consumeP2SH = 1; + } + } + */ + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + if (btchip_context_D.transactionContext.scriptRemaining == 0) { + // Move to next output + btchip_context_D.transactionContext.transactionRemainingInputsOutputs--; + btchip_context_D.transactionContext.transactionCurrentInputOutput++; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; + continue; + } + dataAvailable = (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext.scriptRemaining + ? btchip_context_D.transactionContext.scriptRemaining + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; + break; } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { - PRINTF("Output hashing done\n"); - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; + case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { + PRINTF("Output hashing done\n"); + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Locktime + Expiration + check_transaction_available(4 + 4); + transaction_offset_increase(4 + 4); + + if (btchip_context_D.transactionDataRemaining == 0) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PARSED; + continue; + } else { + btchip_context_D.transactionHashOption = 0; + btchip_context_D.transactionContext.scriptRemaining = + transaction_get_varint(); + btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PROCESS_EXTRA; + continue; + } } - // Locktime + Expiration - check_transaction_available(4+4); - transaction_offset_increase(4+4); - if (btchip_context_D.transactionDataRemaining == 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; - continue; - } else { - btchip_context_D.transactionHashOption = 0; - btchip_context_D.transactionContext.scriptRemaining = - transaction_get_varint(); - btchip_context_D.transactionHashOption = - TRANSACTION_HASH_FULL; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PROCESS_EXTRA; - continue; - } - } + case BTCHIP_TRANSACTION_PROCESS_EXTRA: { + unsigned char dataAvailable; - case BTCHIP_TRANSACTION_PROCESS_EXTRA: { - unsigned char dataAvailable; + if (btchip_context_D.transactionContext.scriptRemaining == 0) { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_PARSED; + continue; + } - if (btchip_context_D.transactionContext.scriptRemaining == - 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; - continue; + if (btchip_context_D.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + + dataAvailable = (btchip_context_D.transactionDataRemaining > + btchip_context_D.transactionContext.scriptRemaining + ? btchip_context_D.transactionContext.scriptRemaining + : btchip_context_D.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; + break; } - if (btchip_context_D.transactionDataRemaining < 1) { - // No more data to read, ok + case BTCHIP_TRANSACTION_PARSED: { + PRINTF("Transaction parsed\n"); goto ok; } - dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext - .scriptRemaining - ? btchip_context_D.transactionContext - .scriptRemaining - : btchip_context_D.transactionDataRemaining); - if (dataAvailable == 0) { + case BTCHIP_TRANSACTION_PRESIGN_READY: { + PRINTF("Presign ready\n"); goto ok; } - transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case BTCHIP_TRANSACTION_PARSED: { - PRINTF("Transaction parsed\n"); - goto ok; - } - - case BTCHIP_TRANSACTION_PRESIGN_READY: { - PRINTF("Presign ready\n"); - goto ok; - } - - case BTCHIP_TRANSACTION_SIGN_READY: { - PRINTF("Sign ready\n"); - goto ok; - } + case BTCHIP_TRANSACTION_SIGN_READY: { + PRINTF("Sign ready\n"); + goto ok; + } } } @@ -632,8 +600,7 @@ void transaction_parse(unsigned char parseMode) { } CATCH_OTHER(e) { PRINTF("Transaction parse - surprise fail\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); THROW(e); } diff --git a/src/main.c b/src/main.c index 609c471..d6cf2cb 100644 --- a/src/main.c +++ b/src/main.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * 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. + ********************************************************************************/ #include "os.h" #include "cx.h" @@ -32,7 +32,7 @@ #include "ui_shared.h" #define __NAME3(a, b, c) a##b##c -#define NAME3(a, b, c) __NAME3(a, b, c) +#define NAME3(a, b, c) __NAME3(a, b, c) #ifndef TARGET_STAX bagl_element_t tmp_element; @@ -40,16 +40,16 @@ bagl_element_t tmp_element; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10 +#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10 #define BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH 8 -#define MAX_CHAR_PER_LINE 25 +#define MAX_CHAR_PER_LINE 25 -#define COLOR_BG_1 0xF9F9F9 -#define COLOR_APP COIN_COLOR_HDR // bitcoin 0xFCB653 -#define COLOR_APP_LIGHT COIN_COLOR_DB // bitcoin 0xFEDBA9 -#define COLOR_BLACK 0x000000 +#define COLOR_BG_1 0xF9F9F9 +#define COLOR_APP COIN_COLOR_HDR // bitcoin 0xFCB653 +#define COLOR_APP_LIGHT COIN_COLOR_DB // bitcoin 0xFEDBA9 +#define COLOR_BLACK 0x000000 -#define COLOR_GRAY 0x999999 +#define COLOR_GRAY 0x999999 #define COLOR_LIGHT_GRAY 0xEEEEEE #ifndef TARGET_STAX @@ -64,39 +64,38 @@ ux_state_t G_ux; bolos_ux_params_t G_ux_params; #else ux_state_t ux; -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 #ifndef TARGET_STAX // override point, but nothing more to do void io_seproxyhal_display(const bagl_element_t *element) { if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { - io_seproxyhal_display_default((bagl_element_t *)element); + io_seproxyhal_display_default((bagl_element_t *) element); } } #endif unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; + case CHANNEL_KEYBOARD: + break; - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); + // multiplexed io exchange over a SPI channel and TLV encapsulated protocol + case CHANNEL_SPI: + if (tx_len) { + io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); + if (channel & IO_RESET_AFTER_REPLIED) { + reset(); + } + return 0; // nothing received from the master so far (it's a tx + // transaction) + } else { + return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, - sizeof(G_io_apdu_buffer), 0); - } - default: - THROW(INVALID_PARAMETER); + default: + THROW(INVALID_PARAMETER); } return 0; } @@ -107,47 +106,47 @@ unsigned char io_event(unsigned char channel) { // needed // can't have more than one tag in the reply, not supported yet. switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); + break; #ifndef TARGET_STAX - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; + case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: + UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); + break; #endif - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - // no break is intentional - __attribute__((fallthrough)); - default: - UX_DEFAULT_EVENT(); - break; + case SEPROXYHAL_TAG_STATUS_EVENT: + if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && + !(U4BE(G_io_seproxyhal_spi_buffer, 3) & + SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { + THROW(EXCEPTION_IO_RESET); + } + // no break is intentional + __attribute__((fallthrough)); + default: + UX_DEFAULT_EVENT(); + break; #ifndef TARGET_STAX - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; + case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: + UX_DISPLAYED_EVENT({}); + break; #endif - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { - // don't redisplay if UX not allowed (pin locked in the common bolos - // ux ?) - if (ux_step_count && UX_ALLOWED) { - // prepare next screen - if(!ux_loop_over_curr_element) { - ux_step = (ux_step + 1) % ux_step_count; + case SEPROXYHAL_TAG_TICKER_EVENT: + UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { + // don't redisplay if UX not allowed (pin locked in the common bolos + // ux ?) + if (ux_step_count && UX_ALLOWED) { + // prepare next screen + if (!ux_loop_over_curr_element) { + ux_step = (ux_step + 1) % ux_step_count; + } + // redisplay screen + UX_REDISPLAY(); } - // redisplay screen - UX_REDISPLAY(); - } - }); - break; + }); + break; } // close the event if not done previously (by a display or whatever) @@ -175,17 +174,17 @@ btchip_altcoin_config_t const C_coin_config = { .p2pkh_version = COIN_P2PKH_VERSION, .p2sh_version = COIN_P2SH_VERSION, .family = COIN_FAMILY, -// unsigned char* iconsuffix;// will use the icon provided on the stack (maybe) + // unsigned char* iconsuffix;// will use the icon provided on the stack (maybe) .coinid = COIN_COINID, .name = COIN_COINID_NAME, .name_short = COIN_COINID_SHORT, #ifdef COIN_FORKID .forkid = COIN_FORKID, -#endif // COIN_FORKID +#endif // COIN_FORKID #ifdef COIN_FLAGS .flags = COIN_FLAGS, -#endif // COIN_FLAGS +#endif // COIN_FLAGS .kind = COIN_KIND, }; @@ -213,7 +212,7 @@ __attribute__((section(".boot"))) int main(int arg0) { check_api_level(CX_COMPAT_APILEVEL); // delegate to bitcoin app/lib libcall_params[0] = "Decred"; - libcall_params[1] = 0x100; // use the Init call, as we won't exit + libcall_params[1] = 0x100; // use the Init call, as we won't exit libcall_params[2] = &coin_config; os_lib_call(&libcall_params); } @@ -229,14 +228,14 @@ __attribute__((section(".boot"))) int main(int arg0) { if (arg0) { // is ID 1 ? - if (((unsigned int *)arg0)[0] != 0x100) { + if (((unsigned int *) arg0)[0] != 0x100) { app_exit(); return 0; } // grab the coin config structure from the first parameter - G_coin_config = (btchip_altcoin_config_t *)((unsigned int *)arg0)[1]; + G_coin_config = (btchip_altcoin_config_t *) ((unsigned int *) arg0)[1]; } else { - G_coin_config = (btchip_altcoin_config_t *)PIC(&C_coin_config); + G_coin_config = (btchip_altcoin_config_t *) PIC(&C_coin_config); } // ensure exception will work as planned @@ -251,7 +250,7 @@ __attribute__((section(".boot"))) int main(int arg0) { #ifdef TARGET_NANOX // grab the current plane mode setting G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX +#endif // TARGET_NANOX btchip_context_init(); @@ -263,7 +262,7 @@ __attribute__((section(".boot"))) int main(int arg0) { #ifdef HAVE_BLE BLE_power(0, NULL); BLE_power(1, "Nano X"); -#endif // HAVE_BLE +#endif // HAVE_BLE app_main(); } @@ -282,6 +281,6 @@ __attribute__((section(".boot"))) int main(int arg0) { END_TRY; } app_exit(); -#endif // USE_LIB_DECRED +#endif // USE_LIB_DECRED return 0; } diff --git a/src/ui/main/ui_main_menu.h b/src/ui/main/ui_main_menu.h index 1cbd819..3b49dc6 100644 --- a/src/ui/main/ui_main_menu.h +++ b/src/ui/main/ui_main_menu.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #pragma once void ui_idle(void); diff --git a/src/ui/main/ui_main_menu_bagl.c b/src/ui/main/ui_main_menu_bagl.c index ee9cb2d..eff255d 100644 --- a/src/ui/main/ui_main_menu_bagl.c +++ b/src/ui/main/ui_main_menu_bagl.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #ifdef HAVE_BAGL #include "ui_main_menu.h" #include "ui_shared.h" @@ -33,15 +33,14 @@ const ux_menu_entry_t menu_settings[]; // change the setting void menu_settings_pubKeyRequestRestriction_change(unsigned int enabled) { - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); + nvm_write((void*) &N_btchip.pubKeyRequestRestriction, &enabled, 1); // go back to the menu entry UX_MENU_DISPLAY(0, menu_main, NULL); } const ux_menu_entry_t menu_settings_pubKeyRequestRestriction[] = { - {NULL, menu_settings_pubKeyRequestRestriction_change, 1, NULL, "Manual approval", NULL, 0, 0}, - {NULL, menu_settings_pubKeyRequestRestriction_change, 0, NULL, "Auto approval", NULL, 0, 0}, - UX_MENU_END -}; + {NULL, menu_settings_pubKeyRequestRestriction_change, 1, NULL, "Manual approval", NULL, 0, 0}, + {NULL, menu_settings_pubKeyRequestRestriction_change, 0, NULL, "Auto approval", NULL, 0, 0}, + UX_MENU_END}; const ux_menu_entry_t menu_settings[] = { {menu_settings_pubKeyRequestRestriction, NULL, 0, NULL, "Public keys", "export approval", 0, 0}, {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, @@ -54,116 +53,111 @@ const ux_menu_entry_t menu_about[] = { const ux_menu_entry_t menu_main[] = { //{NULL, NULL, 0, &NAME3(C_nanos_badge_, COINID, ), "Use wallet to", "view - //accounts", 33, 12}, + // accounts", 33, 12}, {NULL, NULL, 0, NULL, "Use wallet to", "view accounts", 0, 0}, {menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0}, {menu_about, NULL, 0, NULL, "About", NULL, 0, 0}, {NULL, os_sched_exit, 0, &C_nanos_icon_dashboard, "Quit app", NULL, 50, 29}, UX_MENU_END}; -#endif // #if defined(TARGET_NANOS) +#endif // #if defined(TARGET_NANOS) #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) const char* settings_submenu_getter(unsigned int idx); void settings_submenu_selector(unsigned int idx); - void settings_pubkey_export_change(unsigned int enabled) { - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); + nvm_write((void*) &N_btchip.pubKeyRequestRestriction, &enabled, 1); ui_idle(); } ////////////////////////////////////////////////////////////////////////////////////// // Public keys export submenu: -const char* const settings_pubkey_export_getter_values[] = { - "Auto Approval", - "Manual Approval", - "Back" -}; +const char* const settings_pubkey_export_getter_values[] = {"Auto Approval", + "Manual Approval", + "Back"}; const char* settings_pubkey_export_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { - return settings_pubkey_export_getter_values[idx]; - } - return NULL; + if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { + return settings_pubkey_export_getter_values[idx]; + } + return NULL; } void settings_pubkey_export_selector(unsigned int idx) { - switch(idx) { - case 0: - settings_pubkey_export_change(0); - break; - case 1: - settings_pubkey_export_change(1); - break; - default: - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); - } + switch (idx) { + case 0: + settings_pubkey_export_change(0); + break; + case 1: + settings_pubkey_export_change(1); + break; + default: + ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); + } } ////////////////////////////////////////////////////////////////////////////////////// // Settings menu: const char* const settings_submenu_getter_values[] = { - "Public keys export", - "Back", + "Public keys export", + "Back", }; const char* settings_submenu_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_submenu_getter_values)) { - return settings_submenu_getter_values[idx]; - } - return NULL; + if (idx < ARRAYLEN(settings_submenu_getter_values)) { + return settings_submenu_getter_values[idx]; + } + return NULL; } void settings_submenu_selector(unsigned int idx) { - switch(idx) { - case 0: - ux_menulist_init_select(0, settings_pubkey_export_getter, settings_pubkey_export_selector, N_btchip.pubKeyRequestRestriction); - break; - default: - ui_idle(); - } + switch (idx) { + case 0: + ux_menulist_init_select(0, + settings_pubkey_export_getter, + settings_pubkey_export_selector, + N_btchip.pubKeyRequestRestriction); + break; + default: + ui_idle(); + } } ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_idle_flow_1_step, - nn, - { - "Application", - "is ready", - }); -UX_STEP_VALID( - ux_idle_flow_2_step, - pb, - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector), - { - &C_icon_coggle, - "Settings", - }); -UX_STEP_NOCB( - ux_idle_flow_3_step, - bn, - { - "Version", - APPVERSION, - }); -UX_STEP_VALID( - ux_idle_flow_4_step, - pb, - os_sched_exit(-1), - { - &C_icon_dashboard_x, - "Quit", - }); +UX_STEP_NOCB(ux_idle_flow_1_step, + nn, + { + "Application", + "is ready", + }); +UX_STEP_VALID(ux_idle_flow_2_step, + pb, + ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector), + { + &C_icon_coggle, + "Settings", + }); +UX_STEP_NOCB(ux_idle_flow_3_step, + bn, + { + "Version", + APPVERSION, + }); +UX_STEP_VALID(ux_idle_flow_4_step, + pb, + os_sched_exit(-1), + { + &C_icon_dashboard_x, + "Quit", + }); UX_FLOW(ux_idle_flow, - &ux_idle_flow_1_step, - &ux_idle_flow_2_step, - &ux_idle_flow_3_step, - &ux_idle_flow_4_step -); + &ux_idle_flow_1_step, + &ux_idle_flow_2_step, + &ux_idle_flow_3_step, + &ux_idle_flow_4_step); #endif void ui_idle(void) { @@ -174,10 +168,10 @@ void ui_idle(void) { UX_MENU_DISPLAY(0, menu_main, NULL); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) // reserve a display stack slot if none yet - if(G_ux.stack_count == 0) { + if (G_ux.stack_count == 0) { ux_stack_push(); } ux_flow_init(0, ux_idle_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } -#endif // HAVE_BAGL +#endif // HAVE_BAGL diff --git a/src/ui/main/ui_main_menu_nbgl.c b/src/ui/main/ui_main_menu_nbgl.c index f8fca02..b105c82 100644 --- a/src/ui/main/ui_main_menu_nbgl.c +++ b/src/ui/main/ui_main_menu_nbgl.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #ifdef HAVE_NBGL #include "ui_main_menu.h" #include "ui_shared.h" @@ -35,49 +35,45 @@ static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content); #define SWITCH_KEY_EXPORT_TOKEN FIRST_USER_TOKEN #define NB_INFO_FIELDS 2 -static const char* const infoTypes[] = {"Version", "Decred App"}; -static const char* const infoContents[] = {APPVERSION, "(c) 2022 Ledger"}; +static const char *const infoTypes[] = {"Version", "Decred App"}; +static const char *const infoContents[] = {APPVERSION, "(c) 2022 Ledger"}; static nbgl_layoutSwitch_t setting_switch; -void onQuitCallback(void) -{ +void onQuitCallback(void) { os_sched_exit(-1); } static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content) { - if (page == 0) { - setting_switch.text = "Public keys export"; - setting_switch.subText = "Enable automatic key export"; - setting_switch.token = SWITCH_KEY_EXPORT_TOKEN; - setting_switch.tuneId = TUNE_TAP_CASUAL; + if (page == 0) { + setting_switch.text = "Public keys export"; + setting_switch.subText = "Enable automatic key export"; + setting_switch.token = SWITCH_KEY_EXPORT_TOKEN; + setting_switch.tuneId = TUNE_TAP_CASUAL; - content->type = SWITCHES_LIST; - content->switchesList.nbSwitches = 1; - content->switchesList.switches = (nbgl_layoutSwitch_t*) &setting_switch; - } - else if (page == 1) { - content->type = INFOS_LIST; - content->infosList.nbInfos = NB_INFO_FIELDS; - content->infosList.infoTypes = (const char**) infoTypes; - content->infosList.infoContents = (const char**) infoContents; - } - else { - return false; - } - return true; + content->type = SWITCHES_LIST; + content->switchesList.nbSwitches = 1; + content->switchesList.switches = (nbgl_layoutSwitch_t *) &setting_switch; + } else if (page == 1) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char **) infoTypes; + content->infosList.infoContents = (const char **) infoContents; + } else { + return false; + } + return true; } - + static void settingsControlsCallback(int token, uint8_t index) { UNUSED(index); - switch(token) - { + switch (token) { case SWITCH_KEY_EXPORT_TOKEN: setting_switch.initState = !setting_switch.initState; unsigned int setting_value = (unsigned int) !setting_switch.initState; - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &setting_value, 1); + nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &setting_value, 1); displaySettingsMenu(); - break; + break; default: PRINTF("Should not happen !"); break; @@ -85,11 +81,22 @@ static void settingsControlsCallback(int token, uint8_t index) { } static void displaySettingsMenu(void) { - nbgl_useCaseSettings("Stellar settings",0,2,true,ui_idle,settingsNavCallback,settingsControlsCallback); + nbgl_useCaseSettings("Stellar settings", + 0, + 2, + true, + ui_idle, + settingsNavCallback, + settingsControlsCallback); } void ui_idle(void) { - setting_switch.initState = (bool) ! N_btchip.pubKeyRequestRestriction; - nbgl_useCaseHome("Decred",&C_decred_icon_64px, "This app confirms actions on\nthe Decred network.", true, displaySettingsMenu, onQuitCallback); + setting_switch.initState = (bool) !N_btchip.pubKeyRequestRestriction; + nbgl_useCaseHome("Decred", + &C_decred_icon_64px, + "This app confirms actions on\nthe Decred network.", + true, + displaySettingsMenu, + onQuitCallback); } -#endif // HAVE_NBGL +#endif // HAVE_NBGL diff --git a/src/ui/pubkey/ui_pubkey.h b/src/ui/pubkey/ui_pubkey.h index a110b0c..99e519a 100644 --- a/src/ui/pubkey/ui_pubkey.h +++ b/src/ui/pubkey/ui_pubkey.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #pragma once void ui_display_public_key(unsigned char* derivation_path); diff --git a/src/ui/pubkey/ui_pubkey_bagl.c b/src/ui/pubkey/ui_pubkey_bagl.c index ef00c24..24bfec7 100644 --- a/src/ui/pubkey/ui_pubkey_bagl.c +++ b/src/ui/pubkey/ui_pubkey_bagl.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #ifdef HAVE_BAGL #include "ui_main_menu.h" #include "ui_pubkey.h" @@ -29,9 +29,9 @@ unsigned int ui_display_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + unsigned int button_mask_counter); unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + unsigned int button_mask_counter); const bagl_element_t ui_display_address_nanos[] = { @@ -45,7 +45,12 @@ const bagl_element_t ui_display_address_nanos[] = { UI_NANOS_TEXT(2, 0, 26, 128, "path is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Derivation path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(0x83, + 15, + 26, + 98, + vars.tmp_warning.derivation_path, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), @@ -61,8 +66,12 @@ const bagl_element_t ui_display_address_nanos[] = { UI_NANOS_TEXT(6, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), // Hax, avoid wasting space - UI_NANOS_SCROLLING_TEXT(0x86, 15, 26, 98, G_io_apdu_buffer + 199, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_SCROLLING_TEXT(0x86, + 15, + 26, + 98, + G_io_apdu_buffer + 199, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; const bagl_element_t ui_request_pubkey_approval_nanos[] = { UI_NANOS_BACKGROUND(), @@ -70,8 +79,7 @@ const bagl_element_t ui_request_pubkey_approval_nanos[] = { UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), UI_NANOS_TEXT(1, 0, 12, 128, "Export", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, "public key?", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_TEXT(1, 0, 26, 128, "public key?", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; const bagl_element_t ui_display_token_nanos[] = { @@ -80,32 +88,31 @@ const bagl_element_t ui_display_token_nanos[] = { UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), UI_NANOS_TEXT(1, 0, 12, 128, "Confirm token", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, G_io_apdu_buffer + 200, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; - - -unsigned int ui_display_address_nanos_prepro(const bagl_element_t *element) { + UI_NANOS_TEXT(1, 0, 26, 128, G_io_apdu_buffer + 200, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; +unsigned int ui_display_address_nanos_prepro(const bagl_element_t* element) { if (element->component.userid > 0) { unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); if (display) { switch (element->component.userid) { - case 0x83: - ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - case 5: - UX_CALLBACK_SET_INTERVAL(2000); - ux_loop_over_curr_element = 0; // allow next timer to increment ux_step when triggered - break; - case 0x86: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - // ugly ux tricks, loops around last 2 screens - ux_step -= 1; // loops back to previous element on next redraw - ux_loop_over_curr_element = 1; // when the timer will trigger, ux_step won't be incremented, only redraw - break; + case 0x83: + ux_loop_over_curr_element = 1; + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; + case 5: + UX_CALLBACK_SET_INTERVAL(2000); + ux_loop_over_curr_element = + 0; // allow next timer to increment ux_step when triggered + break; + case 0x86: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + // ugly ux tricks, loops around last 2 screens + ux_step -= 1; // loops back to previous element on next redraw + ux_loop_over_curr_element = 1; // when the timer will trigger, ux_step won't be + // incremented, only redraw + break; } } return display; @@ -116,79 +123,68 @@ unsigned int ui_display_address_nanos_prepro(const bagl_element_t *element) { unsigned int ui_display_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { UNUSED(button_mask_counter); - if (ux_step == 3) - { - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - break; - } - } - else if (ux_step >= 4) - { - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } - else - { - if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) - { - // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) - if(ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } + if (ux_step == 3) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: // prepare next screen ux_step = (ux_step + 1) % ux_step_count; // redisplay screen UX_REDISPLAY(); + break; + } + } else if (ux_step >= 4) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; + } + } else { + if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { + // if we were looping over a single element, disable this loop and diffuse the redisplay + // timeout (used by scrolling text) + if (ux_loop_over_curr_element) { + ux_loop_over_curr_element = 0; + ux.callback_interval_ms = 0; + } + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); } } return 0; } unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ + unsigned int button_mask_counter) { UNUSED(button_mask_counter); - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; } return 0; } unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ + unsigned int button_mask_counter) { UNUSED(button_mask_counter); - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_token_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_token_ok(NULL); - break; + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_token_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_token_ok(NULL); + break; } return 0; } @@ -197,152 +193,139 @@ unsigned int ui_display_token_nanos_button(unsigned int button_mask, #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) -UX_STEP_NOCB( - ux_display_public_flow_1_step, - pnn, - { - &C_icon_warning, - "The derivation", - "path is unusual!", - }); -UX_STEP_NOCB( - ux_display_public_flow_2_step, - bnnn_paging, - { - .title = "Derivation path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_VALID( - ux_display_public_flow_3_step, - pnn, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_NOCB( - ux_display_public_flow_4_step, - pnn, - { - &C_icon_validate_14, - "Approve derivation", - "path", - }); -UX_STEP_NOCB( - ux_display_public_flow_5_step, - bnnn_paging, - { - .title = "Address", - .text = G_io_apdu_buffer+200, - }); -UX_STEP_VALID( - ux_display_public_flow_6_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); -UX_STEP_VALID( - ux_display_public_flow_7_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB(ux_display_public_flow_1_step, + pnn, + { + &C_icon_warning, + "The derivation", + "path is unusual!", + }); +UX_STEP_NOCB(ux_display_public_flow_2_step, + bnnn_paging, + { + .title = "Derivation path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_VALID(ux_display_public_flow_3_step, + pnn, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_NOCB(ux_display_public_flow_4_step, + pnn, + { + &C_icon_validate_14, + "Approve derivation", + "path", + }); +UX_STEP_NOCB(ux_display_public_flow_5_step, + bnnn_paging, + { + .title = "Address", + .text = G_io_apdu_buffer + 200, + }); +UX_STEP_VALID(ux_display_public_flow_6_step, + pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); +UX_STEP_VALID(ux_display_public_flow_7_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); UX_FLOW(ux_display_public_with_warning_flow, - &ux_display_public_flow_1_step, - &ux_display_public_flow_2_step, - &ux_display_public_flow_3_step, - &ux_display_public_flow_4_step, - FLOW_BARRIER, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step -); + &ux_display_public_flow_1_step, + &ux_display_public_flow_2_step, + &ux_display_public_flow_3_step, + &ux_display_public_flow_4_step, + FLOW_BARRIER, + &ux_display_public_flow_5_step, + &ux_display_public_flow_6_step, + &ux_display_public_flow_7_step); UX_FLOW(ux_display_public_flow, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step -); + &ux_display_public_flow_5_step, + &ux_display_public_flow_6_step, + &ux_display_public_flow_7_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_VALID( - ux_request_pubkey_approval_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Export", - "public key?", - }); -UX_STEP_VALID( - ux_request_pubkey_approval_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_VALID(ux_request_pubkey_approval_flow_1_step, + pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Export", + "public key?", + }); +UX_STEP_VALID(ux_request_pubkey_approval_flow_2_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); UX_FLOW(ux_request_pubkey_approval_flow, - &ux_request_pubkey_approval_flow_1_step, - &ux_request_pubkey_approval_flow_2_step -); + &ux_request_pubkey_approval_flow_1_step, + &ux_request_pubkey_approval_flow_2_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_VALID( - ux_display_token_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Confirm token", - G_io_apdu_buffer+200, - }); -UX_STEP_VALID( - ux_display_token_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_token_flow, - &ux_display_token_flow_1_step, - &ux_display_token_flow_2_step -); +UX_STEP_VALID(ux_display_token_flow_1_step, + pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Confirm token", + G_io_apdu_buffer + 200, + }); +UX_STEP_VALID(ux_display_token_flow_2_step, + pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_display_token_flow, &ux_display_token_flow_1_step, &ux_display_token_flow_2_step); #endif void ui_display_public_key(unsigned char* derivation_path) { // append a white space at the end of the address to avoid glitch on nano S - strcat((char*)G_io_apdu_buffer + 200, " "); + strcat((char*) G_io_apdu_buffer + 200, " "); - bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); + bip32_print_path(derivation_path, + vars.tmp_warning.derivation_path, + MAX_DERIV_PATH_ASCII_LENGTH); uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); #if defined(TARGET_NANOS) // prepend a white space to the address G_io_apdu_buffer[199] = ' '; - ux_step = is_derivation_path_unusual?0:4; + ux_step = is_derivation_path_unusual ? 0 : 4; ux_step_count = 6; UX_DISPLAY(ui_display_address_nanos, ui_display_address_nanos_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ux_flow_init(0, is_derivation_path_unusual?ux_display_public_with_warning_flow:ux_display_public_flow, NULL); -#endif // TARGET_NANOX + ux_flow_init( + 0, + is_derivation_path_unusual ? ux_display_public_with_warning_flow : ux_display_public_flow, + NULL); +#endif // TARGET_NANOX } -void ui_display_request_pubkey_approval(void) -{ +void ui_display_request_pubkey_approval(void) { #if defined(TARGET_NANOS) // append and prepend a white space to the address ux_step = 0; @@ -350,17 +333,16 @@ void ui_display_request_pubkey_approval(void) UX_DISPLAY(ui_request_pubkey_approval_nanos, NULL); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } -void ui_display_token(void) -{ +void ui_display_token(void) { #if defined(TARGET_NANOS) ux_step = 0; ux_step_count = 1; UX_DISPLAY(ui_display_token_nanos, NULL); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_display_token_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } -#endif // HAVE_BAGL +#endif // HAVE_BAGL diff --git a/src/ui/pubkey/ui_pubkey_nbgl.c b/src/ui/pubkey/ui_pubkey_nbgl.c index cea2cb3..fd45c00 100644 --- a/src/ui/pubkey/ui_pubkey_nbgl.c +++ b/src/ui/pubkey/ui_pubkey_nbgl.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #ifdef HAVE_NBGL #include // bool #include // memset @@ -40,35 +40,26 @@ static pubkey_display_usecase_t display_type; static void confirmationChoiceClbk(bool confirm) { explicit_bzero(confirm_text, sizeof(confirm_text)); - switch(display_type){ + switch (display_type) { case DISPLAY_ADDRESS: - if(confirm) - { - strncpy(confirm_text,"ADDRESS\nAPPROVED", sizeof(confirm_text)); - } - else - { - strncpy(confirm_text,"Address rejected", sizeof(confirm_text)); + if (confirm) { + strncpy(confirm_text, "ADDRESS\nAPPROVED", sizeof(confirm_text)); + } else { + strncpy(confirm_text, "Address rejected", sizeof(confirm_text)); } break; case EXPORT_REQUEST: - if(confirm) - { - strncpy(confirm_text,"PUBLIC KEY\nEXPORTED", sizeof(confirm_text)); - } - else - { - strncpy(confirm_text,"Export cancelled", sizeof(confirm_text)); + if (confirm) { + strncpy(confirm_text, "PUBLIC KEY\nEXPORTED", sizeof(confirm_text)); + } else { + strncpy(confirm_text, "Export cancelled", sizeof(confirm_text)); } break; case DISPLAY_TOKEN: - if(confirm) - { - strncpy(confirm_text,"TOKEN\nAPPROVED", sizeof(confirm_text)); - } - else - { - strncpy(confirm_text,"Token rejected", sizeof(confirm_text)); + if (confirm) { + strncpy(confirm_text, "TOKEN\nAPPROVED", sizeof(confirm_text)); + } else { + strncpy(confirm_text, "Token rejected", sizeof(confirm_text)); } break; default: @@ -76,53 +67,59 @@ static void confirmationChoiceClbk(bool confirm) { break; } confirm ? io_seproxyhal_touch_display_ok(NULL) : io_seproxyhal_touch_display_cancel(NULL); - nbgl_useCaseStatus(confirm_text,confirm,ui_idle); + nbgl_useCaseStatus(confirm_text, confirm, ui_idle); } static void warningChoiceClbk(bool reject) { - if (reject) { - io_seproxyhal_touch_display_cancel(NULL); - nbgl_useCaseStatus("Address rejected",false,ui_idle); - } - else { - nbgl_useCaseAddressConfirmation((char*)G_io_apdu_buffer+200,confirmationChoiceClbk); - } + if (reject) { + io_seproxyhal_touch_display_cancel(NULL); + nbgl_useCaseStatus("Address rejected", false, ui_idle); + } else { + nbgl_useCaseAddressConfirmation((char*) G_io_apdu_buffer + 200, confirmationChoiceClbk); + } } void ui_display_public_key(unsigned char* derivation_path) { display_type = DISPLAY_ADDRESS; - bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); + bip32_print_path(derivation_path, + vars.tmp_warning.derivation_path, + MAX_DERIV_PATH_ASCII_LENGTH); uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); - if(is_derivation_path_unusual) - { + if (is_derivation_path_unusual) { explicit_bzero(choice_text, sizeof(choice_text)); snprintf(choice_text, sizeof(choice_text), "WARNING !\nThe derivation path is\nunusual :\n%s", vars.tmp_warning.derivation_path); - nbgl_useCaseChoice(NULL, choice_text,"Reject if you're not sure","Reject","Continue",warningChoiceClbk); - } - else - { - nbgl_useCaseAddressConfirmation((char*)G_io_apdu_buffer+200,confirmationChoiceClbk); + nbgl_useCaseChoice(NULL, + choice_text, + "Reject if you're not sure", + "Reject", + "Continue", + warningChoiceClbk); + } else { + nbgl_useCaseAddressConfirmation((char*) G_io_apdu_buffer + 200, confirmationChoiceClbk); } } -void ui_display_request_pubkey_approval(void) -{ +void ui_display_request_pubkey_approval(void) { display_type = EXPORT_REQUEST; - nbgl_useCaseChoice(NULL,"Export public key ?",NULL,"Export","Cancel",confirmationChoiceClbk); + nbgl_useCaseChoice(NULL, + "Export public key ?", + NULL, + "Export", + "Cancel", + confirmationChoiceClbk); } -void ui_display_token(void) -{ +void ui_display_token(void) { display_type = DISPLAY_TOKEN; explicit_bzero(choice_text, sizeof(choice_text)); snprintf(choice_text, sizeof(choice_text), "Approve token :\n%s", - (char*)G_io_apdu_buffer+200); - nbgl_useCaseChoice(NULL,choice_text,NULL,"Approve","Reject",confirmationChoiceClbk); + (char*) G_io_apdu_buffer + 200); + nbgl_useCaseChoice(NULL, choice_text, NULL, "Approve", "Reject", confirmationChoiceClbk); } -#endif // HAVE_NBGL +#endif // HAVE_NBGL diff --git a/src/ui/transaction/ui_transaction.h b/src/ui/transaction/ui_transaction.h index 1c383ee..f50d9a1 100644 --- a/src/ui/transaction/ui_transaction.h +++ b/src/ui/transaction/ui_transaction.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #pragma once unsigned int ui_tx_confirm_full_output(void); diff --git a/src/ui/transaction/ui_transaction_bagl.c b/src/ui/transaction/ui_transaction_bagl.c index 3f962aa..448655b 100644 --- a/src/ui/transaction/ui_transaction_bagl.c +++ b/src/ui/transaction/ui_transaction_bagl.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #ifdef HAVE_BAGL #include "ui_transaction.h" #include "ui_shared.h" @@ -34,13 +34,17 @@ const bagl_element_t ui_request_change_path_approval_nanos[] = { UI_NANOS_TEXT(2, 0, 26, 128, "is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Change path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, 15, 26, 98, vars.tmp_warning.derivation_path, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(0x83, + 15, + 26, + 98, + vars.tmp_warning.derivation_path, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t *element) { if (element->component.userid > 0) { @@ -48,8 +52,8 @@ unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t * if (display) { if (element->component.userid & 0x80) { ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); } } return display; @@ -58,7 +62,7 @@ unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t * } unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + unsigned int button_mask_counter); const bagl_element_t ui_verify_nanos[] = { UI_NANOS_BACKGROUND(), @@ -71,14 +75,18 @@ const bagl_element_t ui_verify_nanos[] = { UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), + UI_NANOS_SCROLLING_TEXT(3, + 23, + 26, + 82, + vars.tmp.fullAddress, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(4, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_REGULAR_11px), UI_NANOS_SCROLLING_TEXT(4, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) }; -unsigned int ui_verify_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); +unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); const bagl_element_t ui_verify_output_nanos[] = { @@ -92,8 +100,12 @@ const bagl_element_t ui_verify_output_nanos[] = { UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; + UI_NANOS_SCROLLING_TEXT(3, + 23, + 26, + 82, + vars.tmp.fullAddress, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; unsigned int ui_verify_output_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); @@ -108,7 +120,6 @@ const bagl_element_t ui_finalize_nanos[] = { UI_NANOS_TEXT(2, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) - /* TODO {{BAGL_LABELINE , 0x02, 0, 12, 128, 12, 0, 0, 0 , COLOR_WHITE, COLOR_BLACK, @@ -120,8 +131,7 @@ const bagl_element_t ui_finalize_nanos[] = { vars.tmp.fullAmount, 0, 0, 0, NULL, NULL, NULL }, */ }; -unsigned int ui_finalize_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); +unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); // display or not according to step, and adjust delay unsigned int ui_verify_prepro(const bagl_element_t *element) { @@ -129,15 +139,15 @@ unsigned int ui_verify_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - case 4: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + case 4: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -150,14 +160,14 @@ unsigned int ui_verify_output_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + case 3: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -170,13 +180,13 @@ unsigned int ui_finalize_prepro(const bagl_element_t *element) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -192,24 +202,27 @@ const bagl_element_t ui_verify_message_signature_nanos[] = { UI_NANOS_TEXT(1, 0, 26, 128, "message", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), UI_NANOS_TEXT(2, 0, 12, 128, "Message hash", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAddress, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) -}; -unsigned int -ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); + UI_NANOS_SCROLLING_TEXT(2, + 23, + 26, + 82, + vars.tmp.fullAddress, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; +unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter); unsigned int ui_verify_message_prepro(const bagl_element_t *element) { if (element->component.userid > 0) { unsigned int display = (ux_step == element->component.userid - 1); if (display) { switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL(MAX( - 3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; + case 1: + UX_CALLBACK_SET_INTERVAL(2000); + break; + case 2: + UX_CALLBACK_SET_INTERVAL( + MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); + break; } } return display; @@ -217,17 +230,16 @@ unsigned int ui_verify_message_prepro(const bagl_element_t *element) { return 1; } -unsigned int ui_verify_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { UNUSED(button_mask_counter); switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } @@ -236,326 +248,272 @@ unsigned int ui_verify_output_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { UNUSED(button_mask_counter); switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } -unsigned int ui_finalize_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { +unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { UNUSED(button_mask_counter); switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_verify_ok(NULL); + break; } return 0; } unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { + unsigned int button_mask_counter) { UNUSED(button_mask_counter); switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_message_signature_verify_cancel(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_message_signature_verify_cancel(NULL); + break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_message_signature_verify_ok(NULL); - break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_message_signature_verify_ok(NULL); + break; } return 0; } - unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) -{ +unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, + unsigned int button_mask_counter) { UNUSED(button_mask_counter); - if (ux_step == 3) - { - switch (button_mask) - { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } - else - { - if(button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) - { - // if we were looping over a single element, disable this loop and diffuse the redisplay timeout (used by scrolling text) - if(ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); + if (ux_step == 3) { + switch (button_mask) { + case BUTTON_EVT_RELEASED | BUTTON_LEFT: + io_seproxyhal_touch_display_cancel(NULL); + break; + case BUTTON_EVT_RELEASED | BUTTON_RIGHT: + io_seproxyhal_touch_display_ok(NULL); + break; + } + } else { + if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { + // if we were looping over a single element, disable this loop and diffuse the redisplay + // timeout (used by scrolling text) + if (ux_loop_over_curr_element) { + ux_loop_over_curr_element = 0; + ux.callback_interval_ms = 0; + } + // prepare next screen + ux_step = (ux_step + 1) % ux_step_count; + // redisplay screen + UX_REDISPLAY(); } } return 0; } -#endif // #if defined(TARGET_NANOS) +#endif // #if defined(TARGET_NANOS) #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_sign_flow_1_step, - pnn, - { - &C_icon_certificate, - "Sign", - "message", - }); -UX_STEP_NOCB( - ux_sign_flow_2_step, - bnnn_paging, - { - .title = "Message hash", - .text = vars.tmp.fullAddress, - }); -UX_STEP_VALID( - ux_sign_flow_3_step, - pbb, - io_seproxyhal_touch_message_signature_verify_ok(NULL), - { - &C_icon_validate_14, - "Sign", - "message", - }); -UX_STEP_VALID( - ux_sign_flow_4_step, - pbb, - io_seproxyhal_touch_message_signature_verify_cancel(NULL), - { - &C_icon_crossmark, - "Cancel", - "signature", - }); +UX_STEP_NOCB(ux_sign_flow_1_step, + pnn, + { + &C_icon_certificate, + "Sign", + "message", + }); +UX_STEP_NOCB(ux_sign_flow_2_step, + bnnn_paging, + { + .title = "Message hash", + .text = vars.tmp.fullAddress, + }); +UX_STEP_VALID(ux_sign_flow_3_step, + pbb, + io_seproxyhal_touch_message_signature_verify_ok(NULL), + { + &C_icon_validate_14, + "Sign", + "message", + }); +UX_STEP_VALID(ux_sign_flow_4_step, + pbb, + io_seproxyhal_touch_message_signature_verify_cancel(NULL), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); UX_FLOW(ux_sign_flow, - &ux_sign_flow_1_step, - &ux_sign_flow_2_step, - &ux_sign_flow_3_step, - &ux_sign_flow_4_step -); + &ux_sign_flow_1_step, + &ux_sign_flow_2_step, + &ux_sign_flow_3_step, + &ux_sign_flow_4_step); ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_confirm_full_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction", - }); -UX_STEP_NOCB( - ux_confirm_full_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount - }); -UX_STEP_NOCB( - ux_confirm_full_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB( - ux_confirm_full_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_confirm_full_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send", - }); -UX_STEP_VALID( - ux_confirm_full_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); + pnn, + { + &C_icon_eye, + "Review", + "transaction", + }); +UX_STEP_NOCB(ux_confirm_full_flow_2_step, + bnnn_paging, + {.title = "Amount", .text = vars.tmp.fullAmount}); +UX_STEP_NOCB(ux_confirm_full_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB(ux_confirm_full_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID(ux_confirm_full_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + "and send", + }); +UX_STEP_VALID(ux_confirm_full_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress / Fees: feesAmount UX_FLOW(ux_confirm_full_flow, - &ux_confirm_full_flow_1_step, - &ux_confirm_full_flow_2_step, - &ux_confirm_full_flow_3_step, - &ux_confirm_full_flow_4_step, - &ux_confirm_full_flow_5_step, - &ux_confirm_full_flow_6_step -); + &ux_confirm_full_flow_1_step, + &ux_confirm_full_flow_2_step, + &ux_confirm_full_flow_3_step, + &ux_confirm_full_flow_4_step, + &ux_confirm_full_flow_5_step, + &ux_confirm_full_flow_6_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_confirm_single_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction" - }); -UX_STEP_NOCB( - ux_confirm_single_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount, - }); -UX_STEP_NOCB( - ux_confirm_single_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB( - ux_confirm_single_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_confirm_single_flow_5_step, - pb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - }); -UX_STEP_VALID( - ux_confirm_single_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, {&C_icon_eye, "Review", "transaction"}); +UX_STEP_NOCB(ux_confirm_single_flow_2_step, + bnnn_paging, + { + .title = "Amount", + .text = vars.tmp.fullAmount, + }); +UX_STEP_NOCB(ux_confirm_single_flow_3_step, + bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB(ux_confirm_single_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID(ux_confirm_single_flow_5_step, + pb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + }); +UX_STEP_VALID(ux_confirm_single_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: fullAddress UX_FLOW(ux_confirm_single_flow, - &ux_confirm_single_flow_1_step, - &ux_confirm_single_flow_2_step, - &ux_confirm_single_flow_3_step, - &ux_confirm_single_flow_4_step, - &ux_confirm_single_flow_5_step, - &ux_confirm_single_flow_6_step -); + &ux_confirm_single_flow_1_step, + &ux_confirm_single_flow_2_step, + &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_4_step, + &ux_confirm_single_flow_5_step, + &ux_confirm_single_flow_6_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_finalize_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction" - }); -UX_STEP_NOCB( - ux_finalize_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID( - ux_finalize_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send" - }); -UX_STEP_VALID( - ux_finalize_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); +UX_STEP_NOCB(ux_finalize_flow_1_step, pnn, {&C_icon_eye, "Review", "transaction"}); +UX_STEP_NOCB(ux_finalize_flow_4_step, + bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_VALID(ux_finalize_flow_5_step, + pbb, + io_seproxyhal_touch_verify_ok(NULL), + {&C_icon_validate_14, "Accept", "and send"}); +UX_STEP_VALID(ux_finalize_flow_6_step, + pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); // finalize: confirm transaction / Fees: feesAmount UX_FLOW(ux_finalize_flow, - &ux_finalize_flow_1_step, - &ux_finalize_flow_4_step, - &ux_finalize_flow_5_step, - &ux_finalize_flow_6_step -); + &ux_finalize_flow_1_step, + &ux_finalize_flow_4_step, + &ux_finalize_flow_5_step, + &ux_finalize_flow_6_step); ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_request_change_path_approval_flow_1_step, - pbb, - { - &C_icon_eye, - "The change path", - "is unusual", - }); -UX_STEP_NOCB( - ux_request_change_path_approval_flow_2_step, - bnnn_paging, - { - .title = "Change path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_VALID( - ux_request_change_path_approval_flow_3_step, - pbb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_VALID( - ux_request_change_path_approval_flow_4_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); +UX_STEP_NOCB(ux_request_change_path_approval_flow_1_step, + pbb, + { + &C_icon_eye, + "The change path", + "is unusual", + }); +UX_STEP_NOCB(ux_request_change_path_approval_flow_2_step, + bnnn_paging, + { + .title = "Change path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_VALID(ux_request_change_path_approval_flow_3_step, + pbb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_VALID(ux_request_change_path_approval_flow_4_step, + pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); UX_FLOW(ux_request_change_path_approval_flow, - &ux_request_change_path_approval_flow_1_step, - &ux_request_change_path_approval_flow_2_step, - &ux_request_change_path_approval_flow_3_step, - &ux_request_change_path_approval_flow_4_step -); - -#endif // TARGET_NANOX || TARGET_NANOS2 + &ux_request_change_path_approval_flow_1_step, + &ux_request_change_path_approval_flow_2_step, + &ux_request_change_path_approval_flow_3_step, + &ux_request_change_path_approval_flow_4_step); +#endif // TARGET_NANOX || TARGET_NANOS2 unsigned int ui_tx_confirm_full_output() { if (!prepare_full_output(0)) { @@ -568,19 +526,20 @@ unsigned int ui_tx_confirm_full_output() { UX_DISPLAY(ui_verify_nanos, ui_verify_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_confirm_full_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } unsigned int ui_tx_confirm_single_output() { -// TODO : remove when supporting multi output + // TODO : remove when supporting multi output if (!prepare_single_output()) { return 0; } - snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + - 1); + snprintf(vars.tmp.feesAmount, + sizeof(vars.tmp.feesAmount), + "output #%d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1); #if defined(TARGET_NANOS) ux_step = 0; @@ -588,7 +547,7 @@ unsigned int ui_tx_confirm_single_output() { UX_DISPLAY(ui_verify_output_nanos, ui_verify_output_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_confirm_single_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 +#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } @@ -603,7 +562,7 @@ unsigned int ui_tx_finalize() { UX_DISPLAY(ui_finalize_nanos, ui_finalize_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_finalize_flow, NULL); -#endif // TARGET_NANOX +#endif // TARGET_NANOX return 1; } @@ -618,11 +577,10 @@ void ui_tx_confirm_message_signature() { UX_DISPLAY(ui_verify_message_signature_nanos, ui_verify_message_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_sign_flow, NULL); -#endif // TARGET_NANOX +#endif // TARGET_NANOX } -void ui_tx_request_change_path_approval(unsigned char* change_path) -{ +void ui_tx_request_change_path_approval(unsigned char *change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); #if defined(TARGET_NANOS) // append and prepend a white space to the address @@ -631,7 +589,7 @@ void ui_tx_request_change_path_approval(unsigned char* change_path) UX_DISPLAY(ui_request_change_path_approval_nanos, ui_request_change_path_approval_nanos_prepro); #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_request_change_path_approval_flow, NULL); -#endif // #if TARGET_ID +#endif // #if TARGET_ID } #endif \ No newline at end of file diff --git a/src/ui/transaction/ui_transaction_nbgl.c b/src/ui/transaction/ui_transaction_nbgl.c index 72ba0ff..84ea59e 100644 --- a/src/ui/transaction/ui_transaction_nbgl.c +++ b/src/ui/transaction/ui_transaction_nbgl.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #ifdef HAVE_NBGL #include // bool #include // memset @@ -60,40 +60,38 @@ static void displayTransaction(void); static void reviewStart(void); static void rejectChoice(bool confirm) { - if (confirm){ - nbgl_useCaseStatus(msgs.finishCancel,true,ui_idle); - txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_cancel(NULL) : - io_seproxyhal_touch_verify_cancel(NULL); - } - else{ - if(reviewStarted) - { - displayTransaction(); + if (confirm) { + nbgl_useCaseStatus(msgs.finishCancel, true, ui_idle); + txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_cancel(NULL) + : io_seproxyhal_touch_verify_cancel(NULL); + } else { + if (reviewStarted) { + displayTransaction(); + } else { + reviewStart(); + } } - else - { - reviewStart(); - } - } } - + static void reviewChoice(bool confirm) { - if (confirm) { - if(txType != TX_TYPE_SINGLE_OUTPUT) - { - nbgl_useCaseStatus(msgs.finishOk,true,ui_idle); + if (confirm) { + if (txType != TX_TYPE_SINGLE_OUTPUT) { + nbgl_useCaseStatus(msgs.finishOk, true, ui_idle); + } + txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_ok(NULL) + : io_seproxyhal_touch_verify_ok(NULL); + } else { + rejectUseCaseChoice(); } - txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_ok(NULL) : - io_seproxyhal_touch_verify_ok(NULL); - } - else { - rejectUseCaseChoice(); - } } -static void rejectUseCaseChoice(void) -{ - nbgl_useCaseChoice(NULL,msgs.choiceCancel,NULL,"Yes, cancel",msgs.choiceGoBack,rejectChoice); +static void rejectUseCaseChoice(void) { + nbgl_useCaseChoice(NULL, + msgs.choiceCancel, + NULL, + "Yes, cancel", + msgs.choiceGoBack, + rejectChoice); } static void displayTransaction(void) { @@ -120,20 +118,20 @@ static void reviewStart(void) { pairs[0].value = vars.tmp.fullAmount; pairs[1].item = "To"; pairs[1].value = vars.tmp.fullAddress; - pairs[2].item = "Fees"; + pairs[2].item = "Fees"; pairs[2].value = vars.tmp.feesAmount; pairList.nbPairs = 3; - pairList.pairs = (nbgl_layoutTagValue_t*)pairs; + pairList.pairs = (nbgl_layoutTagValue_t*) pairs; - switch(txType){ + switch (txType) { case TX_TYPE_SINGLE_OUTPUT: pairList.nbPairs = 2; explicit_bzero(genericText, sizeof(genericText)); snprintf(genericText, - sizeof(genericText), - "Review output\n%d of %d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1, - btchip_context_D.totalOutputs); + sizeof(genericText), + "Review output\n%d of %d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1, + btchip_context_D.totalOutputs); msgs.reviewStart = genericText; infoLongPress.text = "Approve output"; infoLongPress.longPressText = "Hold to approve"; @@ -142,7 +140,7 @@ static void reviewStart(void) { pairs[0].item = "Fees"; pairs[0].value = vars.tmp.feesAmount; pairList.nbPairs = 1; - msgs.reviewStart = "Finalize\n transaction"; + msgs.reviewStart = "Finalize\n transaction"; break; case TX_TYPE_SIGN_MESSAGE: pairs[0].item = "Message Hash"; @@ -160,11 +158,15 @@ static void reviewStart(void) { case TX_TYPE_FULL_REVIEW: default: break; - } - - reviewStarted = false; - nbgl_useCaseReviewStart(&C_decred_icon_64px, msgs.reviewStart, NULL, - msgs.reviewCancel, displayTransaction, rejectUseCaseChoice); + } + + reviewStarted = false; + nbgl_useCaseReviewStart(&C_decred_icon_64px, + msgs.reviewStart, + NULL, + msgs.reviewCancel, + displayTransaction, + rejectUseCaseChoice); } unsigned int ui_tx_confirm_full_output() { @@ -188,7 +190,6 @@ unsigned int ui_tx_finalize() { void ui_tx_confirm_message_signature() { txType = TX_TYPE_SIGN_MESSAGE; if (!prepare_message_signature()) { - return; } reviewStart(); @@ -198,29 +199,32 @@ unsigned int ui_tx_confirm_single_output() { txType = TX_TYPE_SINGLE_OUTPUT; if (!prepare_single_output()) { return 0; - } + } reviewStart(); return 1; } static void changePathWarningChoice(bool reject) { - if (reject) { - io_seproxyhal_touch_display_cancel(NULL); - nbgl_useCaseStatus("Transaction rejected",false,ui_idle); - } - else { - io_seproxyhal_touch_display_ok(NULL); - } + if (reject) { + io_seproxyhal_touch_display_cancel(NULL); + nbgl_useCaseStatus("Transaction rejected", false, ui_idle); + } else { + io_seproxyhal_touch_display_ok(NULL); + } } -void ui_tx_request_change_path_approval(unsigned char* change_path) -{ +void ui_tx_request_change_path_approval(unsigned char* change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); explicit_bzero(genericText, sizeof(genericText)); snprintf(genericText, sizeof(genericText), "WARNING !\nThe change path is\nunusual :\n%s", - vars.tmp_warning.derivation_path); - nbgl_useCaseChoice(NULL,genericText,"Reject if you're not sure","Reject","Continue",changePathWarningChoice); + vars.tmp_warning.derivation_path); + nbgl_useCaseChoice(NULL, + genericText, + "Reject if you're not sure", + "Reject", + "Continue", + changePathWarningChoice); } #endif diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 8b9771f..e2fac74 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #include "ui_shared.h" #include "btchip_transaction.h" #include "btchip_bagl_extensions.h" @@ -27,7 +27,7 @@ unsigned int ux_step_count; uint8_t ux_loop_over_curr_element; vars_u_t vars; -unsigned int io_seproxyhal_touch_display_cancel(const void* e){ +unsigned int io_seproxyhal_touch_display_cancel(const void *e) { UNUSED(e); // user denied the transaction, tell the USB side btchip_bagl_user_action_display(0); @@ -35,10 +35,10 @@ unsigned int io_seproxyhal_touch_display_cancel(const void* e){ // redraw ui ui_idle(); #endif - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int io_seproxyhal_touch_display_ok(const void* e){ +unsigned int io_seproxyhal_touch_display_ok(const void *e) { UNUSED(e); // user accepted the transaction, tell the USB side btchip_bagl_user_action_display(1); @@ -46,12 +46,12 @@ unsigned int io_seproxyhal_touch_display_ok(const void* e){ // redraw ui ui_idle(); #endif - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_verify_cancel(const void *e) { UNUSED(e); - + // user denied the transaction, tell the USB side if (!btchip_bagl_user_action(0)) { #ifndef HAVE_NBGL @@ -59,11 +59,11 @@ unsigned int io_seproxyhal_touch_verify_cancel(const void *e) { ui_idle(); #endif } - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_verify_ok(const void *e) { - UNUSED(e); + UNUSED(e); // user accepted the transaction, tell the USB side if (!btchip_bagl_user_action(1)) { #ifndef HAVE_NBGL @@ -71,11 +71,10 @@ unsigned int io_seproxyhal_touch_verify_ok(const void *e) { ui_idle(); #endif } - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int -io_seproxyhal_touch_message_signature_verify_cancel(const void *e) { +unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const void *e) { UNUSED(e); // user denied the transaction, tell the USB side btchip_bagl_user_action_message_signing(0); @@ -83,11 +82,10 @@ io_seproxyhal_touch_message_signature_verify_cancel(const void *e) { // redraw ui ui_idle(); #endif - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } -unsigned int -io_seproxyhal_touch_message_signature_verify_ok(const void *e) { +unsigned int io_seproxyhal_touch_message_signature_verify_ok(const void *e) { UNUSED(e); // user accepted the transaction, tell the USB side btchip_bagl_user_action_message_signing(1); @@ -95,7 +93,7 @@ io_seproxyhal_touch_message_signature_verify_ok(const void *e) { // redraw ui ui_idle(); #endif - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_token_cancel(const void *e) { @@ -106,7 +104,7 @@ unsigned int io_seproxyhal_touch_display_token_cancel(const void *e) { btchip_bagl_user_action_display(0); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } unsigned int io_seproxyhal_touch_display_token_ok(const void *e) { @@ -117,10 +115,9 @@ unsigned int io_seproxyhal_touch_display_token_ok(const void *e) { btchip_bagl_user_action_display(1); // redraw ui ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON + return 0; // DO NOT REDRAW THE BUTTON } - uint8_t prepare_fees() { if (btchip_context_D.transactionContext.relaxed) { memmove(vars.tmp.feesAmount, "UNKNOWN", 7); @@ -128,24 +125,25 @@ uint8_t prepare_fees() { } else { unsigned char fees[8]; unsigned short textSize; - if (transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.totalOutputAmount)) { + if (transaction_amount_sub_be(fees, + btchip_context_D.transactionContext.transactionAmount, + btchip_context_D.totalOutputAmount)) { PRINTF("Fees: %.*H\n", 8, fees); - PRINTF("transactionAmount:: %.*H\n", 8, btchip_context_D.transactionContext.transactionAmount); + PRINTF("transactionAmount:: %.*H\n", + 8, + btchip_context_D.transactionContext.transactionAmount); PRINTF("totalOutputAmount: %.*H\n", 8, btchip_context_D.totalOutputAmount); PRINTF("Error : Fees not consistent"); goto error; } - memmove(vars.tmp.feesAmount, btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); + memmove(vars.tmp.feesAmount, + btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - btchip_context_D.shortCoinIdLength + 1); + (unsigned char *) (vars.tmp.feesAmount + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; } return 1; error: @@ -155,15 +153,23 @@ uint8_t prepare_fees() { uint8_t prepare_message_signature() { uint8_t buffer[32]; - cx_hash((cx_hash_t *)&btchip_context_D.messageHashWitness.header, CX_LAST, - (const unsigned char *) vars.tmp.fullAmount, 0, buffer, 32); + cx_hash((cx_hash_t *) &btchip_context_D.messageHashWitness.header, + CX_LAST, + (const unsigned char *) vars.tmp.fullAmount, + 0, + buffer, + 32); #ifdef HAVE_NBGL - snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H", - 32, buffer); + snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H", 32, buffer); #else - snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H...%.*H", - 8, buffer, 8, buffer + 32 - 8); + snprintf(vars.tmp.fullAddress, + sizeof(vars.tmp.fullAddress), + "%.*H...%.*H", + 8, + buffer, + 8, + buffer + 32 - 8); #endif return 1; } @@ -176,9 +182,9 @@ uint8_t prepare_single_output() { unsigned char versionSize; int addressOffset; unsigned char address[22]; - unsigned short version; // addr prefix, or net id + unsigned short version; // addr prefix, or net id unsigned short textSize; - unsigned char script_version[2]; // Decred thing + unsigned char script_version[2]; // Decred thing vars.tmp.fullAddress[0] = '\0'; btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); @@ -189,21 +195,16 @@ uint8_t prepare_single_output() { PRINTF("amount: %.*H\n", 8, amount); - if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + - offset)) { + if (btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset)) { strcpy(vars.tmp.fullAddress, "OP_RETURN"); - } - else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + - offset)) { + } else if (btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)) { addressOffset = offset + 4; version = btchip_context_D.payToAddressVersion; - } - else { + } else { addressOffset = offset + 3; version = btchip_context_D.payToScriptHashVersion; } if (vars.tmp.fullAddress[0] == 0) { - if (version > 255) { versionSize = 2; address[0] = (version >> 8); @@ -212,13 +213,15 @@ uint8_t prepare_single_output() { versionSize = 1; address[0] = version; } - memmove(address + versionSize, - btchip_context_D.currentOutput + addressOffset, 20); + memmove(address + versionSize, btchip_context_D.currentOutput + addressOffset, 20); // Prepare address - textSize = btchip_public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)tmp, - sizeof(tmp), version, 1); + textSize = btchip_public_key_to_encoded_base58(address, + 20 + versionSize, + (unsigned char *) tmp, + sizeof(tmp), + version, + 1); tmp[textSize] = '\0'; strcpy(vars.tmp.fullAddress, tmp); @@ -226,15 +229,12 @@ uint8_t prepare_single_output() { // Prepare amount - memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); + memmove(vars.tmp.fullAmount, btchip_context_D.shortCoinId, btchip_context_D.shortCoinIdLength); vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - btchip_context_D.shortCoinIdLength + 1); + (unsigned char *) (vars.tmp.fullAmount + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; return 1; } @@ -248,7 +248,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) { unsigned char amount[8], totalOutputAmount[8], fees[8]; char tmp[80]; unsigned char outputPos = 0, changeFound = 0; - unsigned char script_version[2]; // Decred thing + unsigned char script_version[2]; // Decred thing if (btchip_context_D.transactionContext.relaxed && !btchip_context_D.transactionContext.consumeP2SH) { @@ -290,20 +290,17 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); transaction_amount_add_be(totalOutputAmount, totalOutputAmount, amount); - offset += 8; // skip amount + offset += 8; // skip amount btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version - - isOpReturn = btchip_output_script_is_op_return( - btchip_context_D.currentOutput + offset); - isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + - offset); - isOpCreate = btchip_output_script_is_op_create( - btchip_context_D.currentOutput + offset); - isOpCall = btchip_output_script_is_op_call( - btchip_context_D.currentOutput + offset); - PRINTF("REGULAR SCRIPT: %d\n", btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); + offset += 2; // skip script_version + + isOpReturn = btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset); + isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + offset); + isOpCreate = btchip_output_script_is_op_create(btchip_context_D.currentOutput + offset); + isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + offset); + PRINTF("REGULAR SCRIPT: %d\n", + btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)); // Always notify OP_RETURN to the user if (nullAmount && isOpReturn) { if (!checkOnly) { @@ -311,17 +308,14 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } goto error; } - if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + - offset) && - !isP2sh && !(nullAmount && isOpReturn) && - (!isOpCreate && !isOpCall)) { + if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + offset) && !isP2sh && + !(nullAmount && isOpReturn) && (!isOpCreate && !isOpCall)) { if (!checkOnly) { PRINTF("Error : Unrecognized input script"); } goto error; - } else if (!btchip_output_script_is_regular( - btchip_context_D.currentOutput + offset) && - !isP2sh && !(nullAmount && isOpReturn)) { + } else if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + offset) && + !isP2sh && !(nullAmount && isOpReturn)) { if (!checkOnly) { PRINTF("Error : Unrecognized input script"); } @@ -329,12 +323,10 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { unsigned char addressOffset = - (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (memcmp(btchip_context_D.currentOutput + offset + - addressOffset, - btchip_context_D.tmpCtx.output.changeAddress + 1, - 20) == 0) { + (isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (memcmp(btchip_context_D.currentOutput + offset + addressOffset, + btchip_context_D.tmpCtx.output.changeAddress + 1, + 20) == 0) { if (changeFound) { if (!checkOnly) { PRINTF("Error : Multiple change output found"); @@ -356,9 +348,9 @@ uint8_t prepare_full_output(uint8_t checkOnly) { } goto error; } - if (transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - totalOutputAmount)) { + if (transaction_amount_sub_be(fees, + btchip_context_D.transactionContext.transactionAmount, + totalOutputAmount)) { PRINTF("tx_amount: ", 8, btchip_context_D.transactionContext.transactionAmount); PRINTF("total_amount: ", 8, totalOutputAmount); if (!checkOnly) { @@ -370,48 +362,49 @@ uint8_t prepare_full_output(uint8_t checkOnly) { // Format validation message currentPos = 0; offset = 1; - btchip_context_D.tmp = (unsigned char *)tmp; + btchip_context_D.tmp = (unsigned char *) tmp; for (i = 0; i < numberOutputs; i++) { - if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + 2)) { + if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + + 2)) { unsigned char versionSize; int addressOffset; unsigned char address[22]; unsigned short version; btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); - offset += 8; // skip amount + offset += 8; // skip amount btchip_swap_bytes(script_version, btchip_context_D.currentOutput + offset, 2); - offset += 2; // skip script_version + offset += 2; // skip script_version - if (btchip_output_script_is_regular( - btchip_context_D.currentOutput + offset)) { + if (btchip_output_script_is_regular(btchip_context_D.currentOutput + offset)) { addressOffset = offset + 4; version = btchip_context_D.payToAddressVersion; - } else { + } else { addressOffset = offset + 3; version = btchip_context_D.payToScriptHashVersion; } - if (version > 255) { + if (version > 255) { versionSize = 2; address[0] = (version >> 8); address[1] = version; - } else { + } else { versionSize = 1; address[0] = version; } - memmove(address + versionSize, - btchip_context_D.currentOutput + addressOffset, - 20); + memmove(address + versionSize, btchip_context_D.currentOutput + addressOffset, 20); // if we're processing the real output (not the change one) if (currentPos == outputPos) { unsigned short textSize = 0; // Prepare address - textSize = btchip_public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)tmp, - sizeof(tmp), version, 1); + textSize = btchip_public_key_to_encoded_base58(address, + 20 + versionSize, + (unsigned char *) tmp, + sizeof(tmp), + version, + 1); tmp[textSize] = '\0'; strcpy(vars.tmp.fullAddress, tmp); @@ -420,36 +413,26 @@ uint8_t prepare_full_output(uint8_t checkOnly) { PRINTF("prepare amount\n"); memmove(vars.tmp.fullAmount, - btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); - vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = - ' '; + btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); + vars.tmp.fullAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - btchip_context_D.shortCoinIdLength + - 1); + (unsigned char *) (vars.tmp.fullAmount + + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(amount); - vars.tmp - .fullAmount[textSize + - btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.fullAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; // prepare fee display PRINTF("prepare fee display\n"); memmove(vars.tmp.feesAmount, - btchip_context_D.shortCoinId, - btchip_context_D.shortCoinIdLength); - vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = - ' '; + btchip_context_D.shortCoinId, + btchip_context_D.shortCoinIdLength); + vars.tmp.feesAmount[btchip_context_D.shortCoinIdLength] = ' '; btchip_context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - btchip_context_D.shortCoinIdLength + - 1); + (unsigned char *) (vars.tmp.feesAmount + + btchip_context_D.shortCoinIdLength + 1); textSize = btchip_convert_hex_amount_to_displayable(fees); - vars.tmp - .feesAmount[textSize + - btchip_context_D.shortCoinIdLength + 1] = - '\0'; + vars.tmp.feesAmount[textSize + btchip_context_D.shortCoinIdLength + 1] = '\0'; break; } } else { diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 0545d33..7a02d04 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Decred Wallet -* (c) 2022 Ledger -* -* 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. -********************************************************************************/ + * Ledger App - Decred Wallet + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ #pragma once @@ -22,25 +22,60 @@ #include "ux.h" #define COLOR_WHITE 0xFFFFFF -#define UI_NANOS_BACKGROUND() {{BAGL_RECTANGLE,0,0,0,128,32,0,0,BAGL_FILL,0,COLOR_WHITE,0,0},NULL} -#define UI_NANOS_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,0},(char *)text} -#define UI_NANOS_ICON_LEFT(userid, glyph) {{BAGL_ICON,userid,3,12,7,7,0,0,0,COLOR_WHITE,0,0,glyph},NULL} -#define UI_NANOS_ICON_RIGHT(userid, glyph) {{BAGL_ICON,userid,117,13,8,6,0,0,0,COLOR_WHITE,0,0,glyph},NULL} +#define UI_NANOS_BACKGROUND() \ + { {BAGL_RECTANGLE, 0, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0, COLOR_WHITE, 0, 0}, NULL } +#define UI_NANOS_TEXT(userid, x, y, w, text, font) \ + { \ + {BAGL_LABELINE, \ + userid, \ + x, \ + y, \ + w, \ + 12, \ + 0, \ + 0, \ + 0, \ + COLOR_WHITE, \ + 0, \ + font | BAGL_FONT_ALIGNMENT_CENTER, \ + 0}, \ + (char *) text \ + } +#define UI_NANOS_ICON_LEFT(userid, glyph) \ + { {BAGL_ICON, userid, 3, 12, 7, 7, 0, 0, 0, COLOR_WHITE, 0, 0, glyph}, NULL } +#define UI_NANOS_ICON_RIGHT(userid, glyph) \ + { {BAGL_ICON, userid, 117, 13, 8, 6, 0, 0, 0, COLOR_WHITE, 0, 0, glyph}, NULL } // Only one scrolling text per screen can be displayed -#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) {{BAGL_LABELINE,userid,x,y,w,12,0x80|10,0,0,COLOR_WHITE,0,font|BAGL_FONT_ALIGNMENT_CENTER,26},(char *)text} +#define UI_NANOS_SCROLLING_TEXT(userid, x, y, w, text, font) \ + { \ + {BAGL_LABELINE, \ + userid, \ + x, \ + y, \ + w, \ + 12, \ + 0x80 | 10, \ + 0, \ + 0, \ + COLOR_WHITE, \ + 0, \ + font | BAGL_FONT_ALIGNMENT_CENTER, \ + 26}, \ + (char *) text \ + } typedef union { struct { // char addressSummary[40]; // beginning of the output address ... end // of - char fullAddress[43]; // the address - char fullAmount[20]; // full amount - char feesAmount[20]; // fees + char fullAddress[43]; // the address + char fullAmount[20]; // full amount + char feesAmount[20]; // fees } tmp; struct { - char derivation_path [MAX_DERIV_PATH_ASCII_LENGTH]; + char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; } tmp_warning; /* @@ -60,8 +95,8 @@ extern unsigned int ux_step; extern unsigned int ux_step_count; extern uint8_t ux_loop_over_curr_element; -unsigned int io_seproxyhal_touch_display_cancel(const void* e); -unsigned int io_seproxyhal_touch_display_ok(const void* e); +unsigned int io_seproxyhal_touch_display_cancel(const void *e); +unsigned int io_seproxyhal_touch_display_ok(const void *e); unsigned int io_seproxyhal_touch_verify_cancel(const void *e); unsigned int io_seproxyhal_touch_verify_ok(const void *e); From d8ac05ff5aec1abaa424349961b709afd3ffd70d Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 12:17:01 +0200 Subject: [PATCH 22/41] Simplify UI source tree. --- src/ui/{main => }/ui_main_menu.h | 0 src/ui/{main => }/ui_main_menu_bagl.c | 0 src/ui/{main => }/ui_main_menu_nbgl.c | 0 src/ui/{pubkey => }/ui_pubkey.h | 0 src/ui/{pubkey => }/ui_pubkey_bagl.c | 0 src/ui/{pubkey => }/ui_pubkey_nbgl.c | 0 src/ui/{transaction => }/ui_transaction.h | 0 src/ui/{transaction => }/ui_transaction_bagl.c | 0 src/ui/{transaction => }/ui_transaction_nbgl.c | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/ui/{main => }/ui_main_menu.h (100%) rename src/ui/{main => }/ui_main_menu_bagl.c (100%) rename src/ui/{main => }/ui_main_menu_nbgl.c (100%) rename src/ui/{pubkey => }/ui_pubkey.h (100%) rename src/ui/{pubkey => }/ui_pubkey_bagl.c (100%) rename src/ui/{pubkey => }/ui_pubkey_nbgl.c (100%) rename src/ui/{transaction => }/ui_transaction.h (100%) rename src/ui/{transaction => }/ui_transaction_bagl.c (100%) rename src/ui/{transaction => }/ui_transaction_nbgl.c (100%) diff --git a/src/ui/main/ui_main_menu.h b/src/ui/ui_main_menu.h similarity index 100% rename from src/ui/main/ui_main_menu.h rename to src/ui/ui_main_menu.h diff --git a/src/ui/main/ui_main_menu_bagl.c b/src/ui/ui_main_menu_bagl.c similarity index 100% rename from src/ui/main/ui_main_menu_bagl.c rename to src/ui/ui_main_menu_bagl.c diff --git a/src/ui/main/ui_main_menu_nbgl.c b/src/ui/ui_main_menu_nbgl.c similarity index 100% rename from src/ui/main/ui_main_menu_nbgl.c rename to src/ui/ui_main_menu_nbgl.c diff --git a/src/ui/pubkey/ui_pubkey.h b/src/ui/ui_pubkey.h similarity index 100% rename from src/ui/pubkey/ui_pubkey.h rename to src/ui/ui_pubkey.h diff --git a/src/ui/pubkey/ui_pubkey_bagl.c b/src/ui/ui_pubkey_bagl.c similarity index 100% rename from src/ui/pubkey/ui_pubkey_bagl.c rename to src/ui/ui_pubkey_bagl.c diff --git a/src/ui/pubkey/ui_pubkey_nbgl.c b/src/ui/ui_pubkey_nbgl.c similarity index 100% rename from src/ui/pubkey/ui_pubkey_nbgl.c rename to src/ui/ui_pubkey_nbgl.c diff --git a/src/ui/transaction/ui_transaction.h b/src/ui/ui_transaction.h similarity index 100% rename from src/ui/transaction/ui_transaction.h rename to src/ui/ui_transaction.h diff --git a/src/ui/transaction/ui_transaction_bagl.c b/src/ui/ui_transaction_bagl.c similarity index 100% rename from src/ui/transaction/ui_transaction_bagl.c rename to src/ui/ui_transaction_bagl.c diff --git a/src/ui/transaction/ui_transaction_nbgl.c b/src/ui/ui_transaction_nbgl.c similarity index 100% rename from src/ui/transaction/ui_transaction_nbgl.c rename to src/ui/ui_transaction_nbgl.c From c575553975aaad9aa09a0be00f98c059985d605b Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 12:26:18 +0200 Subject: [PATCH 23/41] Add requirements.txt and update conftest. --- test/conftest.py | 112 +++++------------------------------------- test/requirements.txt | 3 ++ 2 files changed, 15 insertions(+), 100 deletions(-) create mode 100644 test/requirements.txt diff --git a/test/conftest.py b/test/conftest.py index 375d3e5..dfe1f85 100755 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,105 +1,17 @@ -import os -# from turtle import back -import pytest -from pathlib import Path - -# from venvtron.lib.python3.8.site-packages.mnemonic.mnemonic import Mnemonic -from ragger import Firmware -from ragger.navigator import NanoNavigator, FatstacksNavigator -from ragger.backend import SpeculosBackend, LedgerCommBackend -from time import sleep - -SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) - -# This variable is needed for Speculos only (physical tests need the application to be already installed) -APPS_DIRECTORY = (Path(__file__).parent / "elfs").resolve() -APP_PREFIX = "decred" - -# This variable will be useful in tests to implement different behavior depending on the firmware -FIRMWARES = [Firmware('nanos', '2.1'), - Firmware('nanosp', '1.0.3'), - Firmware('nanox', '2.0.2'), - Firmware('fat', '1.0')] - -BACKENDS = ["speculos", "ledgercomm", "ledgerwallet"] +# This final fixture will return the properly configured backend client, to be used in tests +from ragger.conftest import configuration +########################### +### CONFIGURATION START ### +########################### MNEMONIC = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" -# Glue to call every test that depends on the firmware once for each required firmware -def pytest_generate_tests(metafunc): - if "firmware" in metafunc.fixturenames: - fw_list = [] - ids = [] - # First pass: enable only demanded firmwares - for fw in FIRMWARES: - if metafunc.config.getoption(fw.device): - fw_list.append(fw) - ids.append(fw.device + " " + fw.version) - # Second pass if no specific firmware demanded: add them all - if not fw_list: - for fw in FIRMWARES: - fw_list.append(fw) - ids.append(fw.device + " " + fw.version) - metafunc.parametrize("firmware", fw_list, ids=ids, scope="session") - -# adding a pytest CLI option "--backend" -def pytest_addoption(parser): - parser.addoption("--backend", action="store", default="speculos") - parser.addoption("--golden_run", action="store_true", default=False) - # Enable ussing --'device' in the pytest command line to restrict testing to specific devices - for fw in FIRMWARES: - parser.addoption("--"+fw.device, action="store_true", help="run on specified device only") - -# accessing the value of the "--backend" option as a fixture -@pytest.fixture(scope="session") -def backend(pytestconfig): - return pytestconfig.getoption("backend") +configuration.OPTIONAL.BACKEND_SCOPE = "session" +configuration.OPTIONAL.CUSTOM_SEED = MNEMONIC -def app_path_from_app_name(app_dir, app_name: str, device: str) -> Path: - assert app_dir.is_dir(), f"{app_dir} is not a directory" - app_path = app_dir / (app_name + "_" + device + ".elf") - assert app_path.is_file(), f"{app_path} must exist" - return app_path - -def prepare_speculos_args(firmware): - speculos_args = ["--model", firmware.device, "--sdk", firmware.version, "--seed", MNEMONIC] - # Uncomment line below to enable display - speculos_args += ["--display", "qt"] - app_path = app_path_from_app_name(APPS_DIRECTORY, APP_PREFIX, firmware.device) - return ([app_path], {"args": speculos_args}) - -# Depending on the "--backend" option value, a different backend is -# instantiated, and the tests will either run on Speculos or on a physical -# device depending on the backend -def create_backend(backend: str, firmware: Firmware): - # if backend.lower() == "ledgercomm": - # return LedgerCommBackend(firmware, interface="hid") - # elif backend.lower() == "ledgerwallet": - # return LedgerWalletBackend(firmware) - if backend.lower() == "speculos": - args, kwargs = prepare_speculos_args(firmware) - return SpeculosBackend(*args, firmware, **kwargs) - else: - raise ValueError(f"Backend '{backend}' is unknown. Valid backends are: {BACKENDS}") - - -@pytest.fixture(scope="session") -def golden_run(pytestconfig): - return pytestconfig.getoption("golden_run") - -@pytest.fixture(scope="session") -def navigator(client, firmware, golden_run): - if firmware.device.startswith("fat"): - return FatstacksNavigator(client, firmware, golden_run) - elif firmware.device.startswith("nano"): - return NanoNavigator(client, firmware, golden_run) - else: - raise ValueError(f"Device '{firmware.device}' is unsupported.") - - -# This final fixture will return the properly configured backend client, to be used in tests -@pytest.fixture(scope="session") -def client(backend, firmware): - with create_backend(backend, firmware) as b: - yield b +######################### +### CONFIGURATION END ### +######################### +# Pull all features from the base ragger conftest using the overridden configuration +pytest_plugins = ("ragger.conftest.base_conftest", ) diff --git a/test/requirements.txt b/test/requirements.txt new file mode 100644 index 0000000..dd7e026 --- /dev/null +++ b/test/requirements.txt @@ -0,0 +1,3 @@ +pytest +ragger[speculos]>=1.6.0 +ragger[ledgerwallet]>=1.6.0 From 8bbe65cdc4e555b6dc8f07fa0996c870d36cf687 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 12:27:37 +0200 Subject: [PATCH 24/41] Add CI workflows. --- .../workflows/build_and_functional_tests.yml | 25 +++++++++++++++++++ .github/workflows/coding_style_checks.yml | 19 ++++++++++++++ .github/workflows/guidelines_enforcer.yml | 15 +++++++++++ 3 files changed, 59 insertions(+) create mode 100644 .github/workflows/build_and_functional_tests.yml create mode 100644 .github/workflows/coding_style_checks.yml create mode 100644 .github/workflows/guidelines_enforcer.yml diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml new file mode 100644 index 0000000..e319ed4 --- /dev/null +++ b/.github/workflows/build_and_functional_tests.yml @@ -0,0 +1,25 @@ +name: Build and run functional tests using ragger through reusable workflow + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + build_application: + name: Build application + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1 + with: + upload_app_binaries_artifact: "compiled_app_binaries" + + ragger_tests: + name: Run ragger tests + needs: build_application + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1 + with: + download_app_binaries_artifact: "compiled_app_binaries" + test_dir: tests diff --git a/.github/workflows/coding_style_checks.yml b/.github/workflows/coding_style_checks.yml new file mode 100644 index 0000000..3201b11 --- /dev/null +++ b/.github/workflows/coding_style_checks.yml @@ -0,0 +1,19 @@ +name: Run coding style check through reusable workflow + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + check_linting: + name: Check linting + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_lint.yml@v1 + with: + source: './src' + extensions: 'h,c' + version: 11 diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml new file mode 100644 index 0000000..7f2ab0d --- /dev/null +++ b/.github/workflows/guidelines_enforcer.yml @@ -0,0 +1,15 @@ +name: Ensure compliance with Ledger guidelines + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + guidelines_enforcer: + name: Guidelines_enforcer + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1 From 34f5ad713859c885b37035bbd4ac599ff5624b94 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 13:05:04 +0200 Subject: [PATCH 25/41] Static analysis fixes. --- Makefile | 2 +- src/btchip_apdu_hash_input_finalize_full.c | 5 ++--- src/btchip_bcd.c | 2 +- src/btchip_context.c | 3 --- src/ui/ui_shared.h | 10 ---------- 5 files changed, 4 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index c19303e..f25182e 100755 --- a/Makefile +++ b/Makefile @@ -171,7 +171,7 @@ APP_SOURCE_PATH += src SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f ifneq ($(TARGET_NAME),TARGET_STAX) -SDK_SOURCE_PATH += lib_ux qrcode +SDK_SOURCE_PATH += lib_ux endif ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index c17ca81..635875f 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -44,7 +44,6 @@ static bool check_output_displayable() { PRINTF("Check if output is displayable\n"); bool displayable = true; unsigned char amount[8], isOpReturn, isP2sh, j, nullAmount = 1; - unsigned char isOpCreate, isOpCall; for (j = 0; j < 8; j++) { if (btchip_context_D.currentOutput[j] != 0) { @@ -61,8 +60,8 @@ static bool check_output_displayable() { isOpReturn = btchip_output_script_is_op_return( btchip_context_D.currentOutput + 8 + 2); // +2 for script version, decred particularity isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + 8 + 2); - isOpCreate = btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); - isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); + btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8 + 2); + btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8 + 2); if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8 + 2) && !isP2sh && !(nullAmount && isOpReturn)) { diff --git a/src/btchip_bcd.c b/src/btchip_bcd.c index 4d0ff70..9edbe96 100644 --- a/src/btchip_bcd.c +++ b/src/btchip_bcd.c @@ -32,7 +32,6 @@ unsigned char btchip_convert_hex_amount_to_displayable(unsigned char *amount) { unsigned char i; unsigned char targetOffset = 0; unsigned char workOffset; - unsigned char j; unsigned char nscratch = SCRATCH_SIZE; unsigned char smin = nscratch - 2; unsigned char comma = 0; @@ -41,6 +40,7 @@ unsigned char btchip_convert_hex_amount_to_displayable(unsigned char *amount) { scratch[i] = 0; } for (i = 0; i < 8; i++) { + unsigned char j; for (j = 0; j < 8; j++) { unsigned char k; unsigned short shifted_in = diff --git a/src/btchip_context.c b/src/btchip_context.c index bbd07a6..efa3c6c 100644 --- a/src/btchip_context.c +++ b/src/btchip_context.c @@ -50,10 +50,7 @@ void btchip_context_init() { } if (!N_btchip.config_valid) { - unsigned char defaultMode; PRINTF("No configuration found\n"); - defaultMode = BTCHIP_MODE_WALLET; - } else { btchip_context_D.payToAddressVersion = G_coin_config->p2pkh_version; btchip_context_D.payToScriptHashVersion = G_coin_config->p2sh_version; diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 7a02d04..e9ae799 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -78,16 +78,6 @@ typedef union { char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; } tmp_warning; - /* - struct { - bagl_icon_details_t icon_details; - unsigned int colors[2]; - unsigned char qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(3)]; - } tmpqr; - - unsigned int dummy; // ensure the whole vars is aligned for the CM0 to - operate correctly - */ } vars_u_t; extern vars_u_t vars; From 3822f07dd1838aa37ed047cdfd15d83d9641e6dd Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 13:07:49 +0200 Subject: [PATCH 26/41] Add short README --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index e69de29..6b545ac 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,12 @@ +# Ledger Decred Application + +## Prerequisite + +Be sure to have your environment correctly set up (see [Getting Started](https://developers.ledger.com/docs/nano-app/introduction/)) and [ledgerblue](https://pypi.org/project/ledgerblue/) installed. + +## Compilation + +``` +make DEBUG=1 # compile optionally with PRINTF +make load # load the app on the Nano using ledgerblue +``` From 259e8d83c5e7a163b2e4e2c284dd79dfdbf83b41 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 15:24:32 +0200 Subject: [PATCH 27/41] Remove blue glyphs + static analysis fix. --- glyphs/blue_badge_transaction.gif | Bin 339 -> 0 bytes glyphs/blue_icon_toggle_reset.gif | Bin 225 -> 0 bytes glyphs/blue_icon_toggle_set.gif | Bin 227 -> 0 bytes src/ui/ui_main_menu_bagl.c | 7 ++++++- 4 files changed, 6 insertions(+), 1 deletion(-) delete mode 100644 glyphs/blue_badge_transaction.gif delete mode 100644 glyphs/blue_icon_toggle_reset.gif delete mode 100644 glyphs/blue_icon_toggle_set.gif diff --git a/glyphs/blue_badge_transaction.gif b/glyphs/blue_badge_transaction.gif deleted file mode 100644 index 131325d4a16f9889cb1efc0709cd4b7aa9130bc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmV-Z0j&NFMd%*x1a>%=!8GA^8LV00000EC2ui05SkF00092 zoR5hREiYOCs@j_v-26=pT3SbTUl;}^KxN|=pclZM;rq1mp+feKi|q!zh;Ddz2~ou* zQqg2Wj!y;611eIhR^M#Oy@4ybSvk_klS7D6(z$^-0J(YLSsJ?+R9qS8KJnC7t#Tga!SS_ z({QtMd#20f^Kh2xn(Q0vK-X64*_WCl4P8<_0r+KP***E}Jo`2Lq&V6~J_Kp79(b&? z=iX(USu3BW9U6bHPmN&5uihzG{E8s*cW(|REeQ$YLwILSIs;MeRK#P%j1nXyMKU4@ lQe}<@PzyRb3uBU-6&(4(u(UQ(-pdk)5=wy4fTV>206Uxbnu-7b diff --git a/glyphs/blue_icon_toggle_reset.gif b/glyphs/blue_icon_toggle_reset.gif deleted file mode 100644 index 450bc869d02ecc35afc46e622e175c5e4afca20d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 225 zcmV<703QEGNk%w1VITk!0J8u9-QC^R*4EO}()RZD?d|RI^78!r{Ls+Q{{H^W&CTB4 z-p=jZ47`T76<|IEzHA^8LV00000EC2ui03ZMo000Dzut`ajNH6QXlTgGYHbual z=oS2p@Hr>=Y?x*0!CneV{8Cb2UlrYbRkT6QDgxWI!9gq*06JE~1l$0M&>}L>STr|?VH8@(Es)oYV7nDO zEa41+93?z1>BoT$Jv Date: Tue, 25 Apr 2023 15:54:56 +0200 Subject: [PATCH 28/41] Update Stax glyphs/icons. --- Makefile | 2 +- glyphs/decred_icon_64px.bmp | Bin 12342 -> 0 bytes glyphs/decred_icon_64px.gif | Bin 0 -> 268 bytes stax_app_decred.gif | Bin 0 -> 129 bytes stax_app_decred_testnet.gif | Bin 0 -> 129 bytes 5 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 glyphs/decred_icon_64px.bmp create mode 100644 glyphs/decred_icon_64px.gif create mode 100644 stax_app_decred.gif create mode 100644 stax_app_decred_testnet.gif diff --git a/Makefile b/Makefile index f25182e..982fcfb 100755 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ DEFINES += $(DEFINES_LIB) ifeq ($(TARGET_NAME),TARGET_NANOS) ICONNAME=nanos_app_$(COIN).gif else ifeq ($(TARGET_NAME),TARGET_STAX) -ICONNAME=stax_app_$(COIN).bmp +ICONNAME=stax_app_$(COIN).gif else ICONNAME=nanox_app_$(COIN).gif endif diff --git a/glyphs/decred_icon_64px.bmp b/glyphs/decred_icon_64px.bmp deleted file mode 100644 index 54ba4a25bfecfde553d75ba05911bb593b8cfe41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12342 zcmeH|u}%ar3`Ccjl7>&9q`Df>^Z%c7M1-?)v-V_?tg@iXNz2)u@w3+;@%eRm-+n%q z^z$t}AHUDj_L`#fN&3rkesW>kuIsZdur9DJur9DJKre9nkJ0l@!6=FYur1C-U}THI zjuJtj?sR%3=;}y4s$bLLe*b+{rxE8pl4S$}5~JKSXz5FDu==;oud}XKofbKjDdveF zP&YphpsOS0d{9L`bVaF1Besa_)(NMS++Md>c2#4SAQr1|Gl;-svlbHQG~y(DkO%}M zXmnF(=}TR5RMbaA1gq;P;xt-QK!7H3pxH(OK7y-!?no~uo61Lss?i`I?cnT73BOfx z7a$PVuNMiqTiQ>LP<9#StiA;8i$EhhVvlI>F#AvVwa05;jD zw$fg*ig`{6Y>g9x)_o z{=zVktY=Q*`4_Li_dop=$a>;M1& diff --git a/glyphs/decred_icon_64px.gif b/glyphs/decred_icon_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..dbc4fdee994ec45b2a13d9610cdf445ec49aa641 GIT binary patch literal 268 zcmV+n0rUPxNk%v~VL$*t0Du4h00030|Nkri0000$06+i$0_%*AsmtvTqnxzbi?iOm z`wxcVcmd{#qEX7WrscA0OaoPY&bUkMHsp&>$(e}-8c7M+`RM4G+PSFOSJ~=12P&M6T3%oRT zOhx7p3)AfU%sYiV3|(!V%@Bmt#yqY3eWnE-EiOhrF1^i;X1<&dtey^E&V8?qi5`CH S{|_*rz<~q{8ax=G0028p$$3Hm literal 0 HcmV?d00001 diff --git a/stax_app_decred.gif b/stax_app_decred.gif new file mode 100644 index 0000000000000000000000000000000000000000..42b500c56dcbd71e6c6fc0752ce3c7e45c9f02d5 GIT binary patch literal 129 zcmZ?wbh9u|RA5kGXkcUjg8%>j>wsvG2m@0>Pyfo(Z}}I`;k$8q-LcB=XLTR2Go96# zcI~C@iXf-;3)ih{yP}xQuJ!cs8I2te_#$+e_)jVay_mCQ%K0??rQCrVcg2`oWX<21 g9Mv6e_CLY-eN;`_{=1pUK5_A{zW=e?&%j^}0JoPnf&c&j literal 0 HcmV?d00001 diff --git a/stax_app_decred_testnet.gif b/stax_app_decred_testnet.gif new file mode 100644 index 0000000000000000000000000000000000000000..42b500c56dcbd71e6c6fc0752ce3c7e45c9f02d5 GIT binary patch literal 129 zcmZ?wbh9u|RA5kGXkcUjg8%>j>wsvG2m@0>Pyfo(Z}}I`;k$8q-LcB=XLTR2Go96# zcI~C@iXf-;3)ih{yP}xQuJ!cs8I2te_#$+e_)jVay_mCQ%K0??rQCrVcg2`oWX<21 g9Mv6e_CLY-eN;`_{=1pUK5_A{zW=e?&%j^}0JoPnf&c&j literal 0 HcmV?d00001 From 61f62dd66d20a314a8b9a5005ee6940b729a9491 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Tue, 25 Apr 2023 16:47:06 +0200 Subject: [PATCH 29/41] Remove useless --dep flag in APP_LOAD_FLAGS --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 982fcfb..5f5eae1 100755 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ APPVERSION_M=1 APPVERSION_N=3 APPVERSION_P=13 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) -APP_LOAD_FLAGS=--appFlags 0x250 --dep Decred:$(APPVERSION) +APP_LOAD_FLAGS=--appFlags 0x250 # simplify for tests ifndef COIN From 1c50c19b6dc50170a5767d0f63bfa39bb447bec4 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Wed, 26 Apr 2023 08:57:55 +0200 Subject: [PATCH 30/41] Update test dir in CI. --- .github/workflows/build_and_functional_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml index e319ed4..30509b3 100644 --- a/.github/workflows/build_and_functional_tests.yml +++ b/.github/workflows/build_and_functional_tests.yml @@ -22,4 +22,4 @@ jobs: uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1 with: download_app_binaries_artifact: "compiled_app_binaries" - test_dir: tests + test_dir: test From b118638e5674195672a6972fe36dcd3c14925fef Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Wed, 26 Apr 2023 09:17:42 +0200 Subject: [PATCH 31/41] Update tests. --- Makefile | 2 +- test/fail.py | 99 ++++--- .../nanos/test_1to2_get_pubkey/00000.png | Bin 0 -> 489 bytes .../nanos/test_1to2_get_pubkey/00001.png | Bin 0 -> 492 bytes .../nanos/test_1to2_get_pubkey/00002.png | Bin 0 -> 313 bytes .../nanos/test_1to2_get_pubkey/00003.png | Bin 0 -> 341 bytes .../nanos/test_1to2_get_pubkey/00004.png | Bin 0 -> 336 bytes .../test_1to2_hash_input_finalize/00000.png | Bin 0 -> 374 bytes .../test_1to2_hash_input_finalize/00001.png | Bin 0 -> 319 bytes .../test_1to2_hash_input_finalize/00002.png | Bin 0 -> 512 bytes .../test_1to2_hash_input_finalize/00003.png | Bin 0 -> 499 bytes .../test_1to2_hash_input_finalize/00004.png | Bin 0 -> 332 bytes .../test_1to2_hash_input_finalize/00005.png | Bin 0 -> 414 bytes .../test_1to2_hash_input_finalize/00006.png | Bin 0 -> 336 bytes .../test_1to2_warning_finalize/00000.png | Bin 0 -> 465 bytes .../test_1to2_warning_finalize/00001.png | Bin 0 -> 507 bytes .../test_1to2_warning_finalize/00002.png | Bin 0 -> 379 bytes .../test_1to2_warning_finalize/00003.png | Bin 0 -> 494 bytes .../test_1to2_warning_finalize/00004.png | Bin 0 -> 333 bytes .../test_1to2_warning_finalize_1/00000.png | Bin 0 -> 343 bytes .../test_1to2_warning_finalize_1/00001.png | Bin 0 -> 365 bytes .../test_1to2_warning_finalize_1/00002.png | Bin 0 -> 524 bytes .../test_1to2_warning_finalize_1/00003.png | Bin 0 -> 499 bytes .../test_1to2_warning_finalize_1/00004.png | Bin 0 -> 324 bytes .../test_1to2_warning_finalize_2/00000.png | Bin 0 -> 350 bytes .../test_1to2_warning_finalize_2/00001.png | Bin 0 -> 319 bytes .../test_1to2_warning_finalize_2/00002.png | Bin 0 -> 512 bytes .../test_1to2_warning_finalize_2/00003.png | Bin 0 -> 499 bytes .../test_1to2_warning_finalize_2/00004.png | Bin 0 -> 324 bytes .../test_1to2_warning_finalize_3/00000.png | Bin 0 -> 374 bytes .../test_1to2_warning_finalize_3/00001.png | Bin 0 -> 332 bytes .../test_1to2_warning_finalize_3/00002.png | Bin 0 -> 414 bytes .../nanos/test_2to2_finalize_1/00000.png | Bin 0 -> 374 bytes .../nanos/test_2to2_finalize_1/00001.png | Bin 0 -> 329 bytes .../nanos/test_2to2_finalize_1/00002.png | Bin 0 -> 521 bytes .../nanos/test_2to2_finalize_1/00003.png | Bin 0 -> 503 bytes .../nanos/test_2to2_finalize_1/00004.png | Bin 0 -> 319 bytes .../nanos/test_2to2_finalize_1/00005.png | Bin 0 -> 342 bytes .../nanos/test_2to2_finalize_1/00006.png | Bin 0 -> 414 bytes .../nanos/test_2to2_finalize_1/00007.png | Bin 0 -> 336 bytes .../nanos/test_decred_sign_message/00000.png | Bin 0 -> 368 bytes .../nanos/test_decred_sign_message/00001.png | Bin 0 -> 509 bytes .../nanos/test_decred_sign_message/00002.png | Bin 0 -> 502 bytes .../nanos/test_decred_sign_message/00003.png | Bin 0 -> 417 bytes .../nanos/test_decred_sign_message/00004.png | Bin 0 -> 336 bytes .../nanosp/test_1to2_get_pubkey/00000.png | Bin 0 -> 701 bytes .../nanosp/test_1to2_get_pubkey/00001.png | Bin 0 -> 364 bytes .../nanosp/test_1to2_get_pubkey/00002.png | Bin 0 -> 368 bytes .../test_1to2_hash_input_finalize/00000.png | Bin 0 -> 414 bytes .../test_1to2_hash_input_finalize/00001.png | Bin 0 -> 380 bytes .../test_1to2_hash_input_finalize/00002.png | Bin 0 -> 713 bytes .../test_1to2_hash_input_finalize/00003.png | Bin 0 -> 379 bytes .../test_1to2_hash_input_finalize/00004.png | Bin 0 -> 472 bytes .../test_1to2_hash_input_finalize/00005.png | Bin 0 -> 368 bytes .../test_1to2_warning_finalize/00000.png | Bin 0 -> 529 bytes .../test_1to2_warning_finalize/00001.png | Bin 0 -> 554 bytes .../test_1to2_warning_finalize/00002.png | Bin 0 -> 574 bytes .../test_1to2_warning_finalize/00003.png | Bin 0 -> 356 bytes .../test_1to2_warning_finalize_1/00000.png | Bin 0 -> 389 bytes .../test_1to2_warning_finalize_1/00001.png | Bin 0 -> 426 bytes .../test_1to2_warning_finalize_1/00002.png | Bin 0 -> 721 bytes .../test_1to2_warning_finalize_1/00003.png | Bin 0 -> 347 bytes .../test_1to2_warning_finalize_2/00000.png | Bin 0 -> 397 bytes .../test_1to2_warning_finalize_2/00001.png | Bin 0 -> 380 bytes .../test_1to2_warning_finalize_2/00002.png | Bin 0 -> 713 bytes .../test_1to2_warning_finalize_2/00003.png | Bin 0 -> 347 bytes .../test_1to2_warning_finalize_3/00000.png | Bin 0 -> 414 bytes .../test_1to2_warning_finalize_3/00001.png | Bin 0 -> 379 bytes .../test_1to2_warning_finalize_3/00002.png | Bin 0 -> 472 bytes .../nanosp/test_2to2_finalize_1/00000.png | Bin 0 -> 414 bytes .../nanosp/test_2to2_finalize_1/00001.png | Bin 0 -> 381 bytes .../nanosp/test_2to2_finalize_1/00002.png | Bin 0 -> 750 bytes .../nanosp/test_2to2_finalize_1/00003.png | Bin 0 -> 390 bytes .../nanosp/test_2to2_finalize_1/00004.png | Bin 0 -> 472 bytes .../nanosp/test_2to2_finalize_1/00005.png | Bin 0 -> 368 bytes .../nanosp/test_decred_sign_message/00000.png | Bin 0 -> 415 bytes .../nanosp/test_decred_sign_message/00001.png | Bin 0 -> 671 bytes .../nanosp/test_decred_sign_message/00002.png | Bin 0 -> 487 bytes .../nanosp/test_decred_sign_message/00003.png | Bin 0 -> 368 bytes .../nanox/test_1to2_get_pubkey/00000.png | Bin 0 -> 701 bytes .../nanox/test_1to2_get_pubkey/00001.png | Bin 0 -> 364 bytes .../nanox/test_1to2_get_pubkey/00002.png | Bin 0 -> 368 bytes .../test_1to2_hash_input_finalize/00000.png | Bin 0 -> 414 bytes .../test_1to2_hash_input_finalize/00001.png | Bin 0 -> 380 bytes .../test_1to2_hash_input_finalize/00002.png | Bin 0 -> 713 bytes .../test_1to2_hash_input_finalize/00003.png | Bin 0 -> 379 bytes .../test_1to2_hash_input_finalize/00004.png | Bin 0 -> 472 bytes .../test_1to2_hash_input_finalize/00005.png | Bin 0 -> 368 bytes .../test_1to2_warning_finalize/00000.png | Bin 0 -> 529 bytes .../test_1to2_warning_finalize/00001.png | Bin 0 -> 554 bytes .../test_1to2_warning_finalize/00002.png | Bin 0 -> 574 bytes .../test_1to2_warning_finalize/00003.png | Bin 0 -> 356 bytes .../test_1to2_warning_finalize_1/00000.png | Bin 0 -> 389 bytes .../test_1to2_warning_finalize_1/00001.png | Bin 0 -> 426 bytes .../test_1to2_warning_finalize_1/00002.png | Bin 0 -> 721 bytes .../test_1to2_warning_finalize_1/00003.png | Bin 0 -> 347 bytes .../test_1to2_warning_finalize_2/00000.png | Bin 0 -> 397 bytes .../test_1to2_warning_finalize_2/00001.png | Bin 0 -> 380 bytes .../test_1to2_warning_finalize_2/00002.png | Bin 0 -> 713 bytes .../test_1to2_warning_finalize_2/00003.png | Bin 0 -> 347 bytes .../test_1to2_warning_finalize_3/00000.png | Bin 0 -> 414 bytes .../test_1to2_warning_finalize_3/00001.png | Bin 0 -> 379 bytes .../test_1to2_warning_finalize_3/00002.png | Bin 0 -> 472 bytes .../nanox/test_2to2_finalize_1/00000.png | Bin 0 -> 414 bytes .../nanox/test_2to2_finalize_1/00001.png | Bin 0 -> 381 bytes .../nanox/test_2to2_finalize_1/00002.png | Bin 0 -> 750 bytes .../nanox/test_2to2_finalize_1/00003.png | Bin 0 -> 390 bytes .../nanox/test_2to2_finalize_1/00004.png | Bin 0 -> 472 bytes .../nanox/test_2to2_finalize_1/00005.png | Bin 0 -> 368 bytes .../nanox/test_decred_sign_message/00000.png | Bin 0 -> 415 bytes .../nanox/test_decred_sign_message/00001.png | Bin 0 -> 671 bytes .../nanox/test_decred_sign_message/00002.png | Bin 0 -> 487 bytes .../nanox/test_decred_sign_message/00003.png | Bin 0 -> 368 bytes .../stax/test_1to2_get_pubkey/00000.png | Bin 0 -> 12646 bytes .../stax/test_1to2_get_pubkey/00001.png | Bin 0 -> 4944 bytes .../stax/test_1to2_get_pubkey/00002.png | Bin 0 -> 9215 bytes .../test_1to2_hash_input_finalize/00000.png | Bin 0 -> 8176 bytes .../test_1to2_hash_input_finalize/00001.png | Bin 0 -> 15536 bytes .../test_1to2_hash_input_finalize/00002.png | Bin 0 -> 8545 bytes .../test_1to2_hash_input_finalize/00003.png | Bin 0 -> 5086 bytes .../test_1to2_hash_input_finalize/00004.png | Bin 0 -> 9215 bytes .../stax/test_1to2_warning_finalize/00000.png | Bin 0 -> 13590 bytes .../stax/test_1to2_warning_finalize/00001.png | Bin 0 -> 8207 bytes .../stax/test_1to2_warning_finalize/00002.png | Bin 0 -> 13653 bytes .../stax/test_1to2_warning_finalize/00003.png | Bin 0 -> 8484 bytes .../stax/test_1to2_warning_finalize/00004.png | Bin 0 -> 8179 bytes .../stax/test_1to2_warning_finalize/00005.png | Bin 0 -> 13310 bytes .../stax/test_1to2_warning_finalize/00006.png | Bin 0 -> 8484 bytes .../stax/test_1to2_warning_finalize/00007.png | Bin 0 -> 8078 bytes .../stax/test_1to2_warning_finalize/00008.png | Bin 0 -> 7702 bytes .../stax/test_1to2_warning_finalize/00009.png | Bin 0 -> 8545 bytes .../stax/test_2to2_finalize_1/00000.png | Bin 0 -> 8176 bytes .../stax/test_2to2_finalize_1/00001.png | Bin 0 -> 15571 bytes .../stax/test_2to2_finalize_1/00002.png | Bin 0 -> 8545 bytes .../stax/test_2to2_finalize_1/00003.png | Bin 0 -> 5086 bytes .../stax/test_2to2_finalize_1/00004.png | Bin 0 -> 9215 bytes .../stax/test_decred_sign_message/00000.png | Bin 0 -> 8207 bytes .../stax/test_decred_sign_message/00001.png | Bin 0 -> 12743 bytes .../stax/test_decred_sign_message/00002.png | Bin 0 -> 8557 bytes .../stax/test_decred_sign_message/00003.png | Bin 0 -> 4293 bytes .../stax/test_decred_sign_message/00004.png | Bin 0 -> 9215 bytes test/test_1to2.py | 163 +++++++----- test/test_1to2_warning_change.py | 208 +++++++-------- test/test_2to2.py | 248 +++++++++--------- test/test_sign_message.py | 67 +++-- 145 files changed, 409 insertions(+), 378 deletions(-) mode change 100755 => 100644 test/fail.py create mode 100644 test/snapshots/nanos/test_1to2_get_pubkey/00000.png create mode 100644 test/snapshots/nanos/test_1to2_get_pubkey/00001.png create mode 100644 test/snapshots/nanos/test_1to2_get_pubkey/00002.png create mode 100644 test/snapshots/nanos/test_1to2_get_pubkey/00003.png create mode 100644 test/snapshots/nanos/test_1to2_get_pubkey/00004.png create mode 100644 test/snapshots/nanos/test_1to2_hash_input_finalize/00000.png create mode 100644 test/snapshots/nanos/test_1to2_hash_input_finalize/00001.png create mode 100644 test/snapshots/nanos/test_1to2_hash_input_finalize/00002.png create mode 100644 test/snapshots/nanos/test_1to2_hash_input_finalize/00003.png create mode 100644 test/snapshots/nanos/test_1to2_hash_input_finalize/00004.png create mode 100644 test/snapshots/nanos/test_1to2_hash_input_finalize/00005.png create mode 100644 test/snapshots/nanos/test_1to2_hash_input_finalize/00006.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize/00000.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize/00001.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize/00002.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize/00003.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize/00004.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_1/00000.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_1/00001.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_1/00002.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_1/00003.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_1/00004.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_2/00000.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_2/00001.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_2/00002.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_2/00003.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_2/00004.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_3/00000.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_3/00001.png create mode 100644 test/snapshots/nanos/test_1to2_warning_finalize_3/00002.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00000.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00001.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00002.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00003.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00004.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00005.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00006.png create mode 100644 test/snapshots/nanos/test_2to2_finalize_1/00007.png create mode 100644 test/snapshots/nanos/test_decred_sign_message/00000.png create mode 100644 test/snapshots/nanos/test_decred_sign_message/00001.png create mode 100644 test/snapshots/nanos/test_decred_sign_message/00002.png create mode 100644 test/snapshots/nanos/test_decred_sign_message/00003.png create mode 100644 test/snapshots/nanos/test_decred_sign_message/00004.png create mode 100644 test/snapshots/nanosp/test_1to2_get_pubkey/00000.png create mode 100644 test/snapshots/nanosp/test_1to2_get_pubkey/00001.png create mode 100644 test/snapshots/nanosp/test_1to2_get_pubkey/00002.png create mode 100644 test/snapshots/nanosp/test_1to2_hash_input_finalize/00000.png create mode 100644 test/snapshots/nanosp/test_1to2_hash_input_finalize/00001.png create mode 100644 test/snapshots/nanosp/test_1to2_hash_input_finalize/00002.png create mode 100644 test/snapshots/nanosp/test_1to2_hash_input_finalize/00003.png create mode 100644 test/snapshots/nanosp/test_1to2_hash_input_finalize/00004.png create mode 100644 test/snapshots/nanosp/test_1to2_hash_input_finalize/00005.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize/00000.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize/00001.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize/00002.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize/00003.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_1/00000.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_1/00001.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_1/00002.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_1/00003.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_2/00000.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_2/00001.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_2/00002.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_2/00003.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_3/00000.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_3/00001.png create mode 100644 test/snapshots/nanosp/test_1to2_warning_finalize_3/00002.png create mode 100644 test/snapshots/nanosp/test_2to2_finalize_1/00000.png create mode 100644 test/snapshots/nanosp/test_2to2_finalize_1/00001.png create mode 100644 test/snapshots/nanosp/test_2to2_finalize_1/00002.png create mode 100644 test/snapshots/nanosp/test_2to2_finalize_1/00003.png create mode 100644 test/snapshots/nanosp/test_2to2_finalize_1/00004.png create mode 100644 test/snapshots/nanosp/test_2to2_finalize_1/00005.png create mode 100644 test/snapshots/nanosp/test_decred_sign_message/00000.png create mode 100644 test/snapshots/nanosp/test_decred_sign_message/00001.png create mode 100644 test/snapshots/nanosp/test_decred_sign_message/00002.png create mode 100644 test/snapshots/nanosp/test_decred_sign_message/00003.png create mode 100644 test/snapshots/nanox/test_1to2_get_pubkey/00000.png create mode 100644 test/snapshots/nanox/test_1to2_get_pubkey/00001.png create mode 100644 test/snapshots/nanox/test_1to2_get_pubkey/00002.png create mode 100644 test/snapshots/nanox/test_1to2_hash_input_finalize/00000.png create mode 100644 test/snapshots/nanox/test_1to2_hash_input_finalize/00001.png create mode 100644 test/snapshots/nanox/test_1to2_hash_input_finalize/00002.png create mode 100644 test/snapshots/nanox/test_1to2_hash_input_finalize/00003.png create mode 100644 test/snapshots/nanox/test_1to2_hash_input_finalize/00004.png create mode 100644 test/snapshots/nanox/test_1to2_hash_input_finalize/00005.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize/00000.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize/00001.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize/00002.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize/00003.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_1/00000.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_1/00001.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_1/00002.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_1/00003.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_2/00000.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_2/00001.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_2/00002.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_2/00003.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_3/00000.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_3/00001.png create mode 100644 test/snapshots/nanox/test_1to2_warning_finalize_3/00002.png create mode 100644 test/snapshots/nanox/test_2to2_finalize_1/00000.png create mode 100644 test/snapshots/nanox/test_2to2_finalize_1/00001.png create mode 100644 test/snapshots/nanox/test_2to2_finalize_1/00002.png create mode 100644 test/snapshots/nanox/test_2to2_finalize_1/00003.png create mode 100644 test/snapshots/nanox/test_2to2_finalize_1/00004.png create mode 100644 test/snapshots/nanox/test_2to2_finalize_1/00005.png create mode 100644 test/snapshots/nanox/test_decred_sign_message/00000.png create mode 100644 test/snapshots/nanox/test_decred_sign_message/00001.png create mode 100644 test/snapshots/nanox/test_decred_sign_message/00002.png create mode 100644 test/snapshots/nanox/test_decred_sign_message/00003.png create mode 100644 test/snapshots/stax/test_1to2_get_pubkey/00000.png create mode 100644 test/snapshots/stax/test_1to2_get_pubkey/00001.png create mode 100644 test/snapshots/stax/test_1to2_get_pubkey/00002.png create mode 100644 test/snapshots/stax/test_1to2_hash_input_finalize/00000.png create mode 100644 test/snapshots/stax/test_1to2_hash_input_finalize/00001.png create mode 100644 test/snapshots/stax/test_1to2_hash_input_finalize/00002.png create mode 100644 test/snapshots/stax/test_1to2_hash_input_finalize/00003.png create mode 100644 test/snapshots/stax/test_1to2_hash_input_finalize/00004.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00000.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00001.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00002.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00003.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00004.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00005.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00006.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00007.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00008.png create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00009.png create mode 100644 test/snapshots/stax/test_2to2_finalize_1/00000.png create mode 100644 test/snapshots/stax/test_2to2_finalize_1/00001.png create mode 100644 test/snapshots/stax/test_2to2_finalize_1/00002.png create mode 100644 test/snapshots/stax/test_2to2_finalize_1/00003.png create mode 100644 test/snapshots/stax/test_2to2_finalize_1/00004.png create mode 100644 test/snapshots/stax/test_decred_sign_message/00000.png create mode 100644 test/snapshots/stax/test_decred_sign_message/00001.png create mode 100644 test/snapshots/stax/test_decred_sign_message/00002.png create mode 100644 test/snapshots/stax/test_decred_sign_message/00003.png create mode 100644 test/snapshots/stax/test_decred_sign_message/00004.png diff --git a/Makefile b/Makefile index 5f5eae1..b8e9b3c 100755 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ APP_LOAD_PARAMS += --path $(APP_PATH) DEFINES_LIB =# Decred IS the lib APP_LOAD_FLAGS=--appFlags 0xa50 else ifeq ($(COIN),decred_testnet) -# Decred mainnet +# Decred testnet DEFINES += COIN_P2PKH_VERSION=3873 COIN_P2SH_VERSION=3836 COIN_FAMILY=1 COIN_COINID=\"Decred\" COIN_COINID_HEADER=\"DECRED\" COIN_COLOR_HDR=0x5482ff COIN_COLOR_DB=0xB2E8CB COIN_COINID_NAME=\"Decred\" COIN_COINID_SHORT=\"TDCR\" COIN_KIND=COIN_KIND_DECRED_TESTNET APPNAME ="Decred Test" APP_LOAD_PARAMS += --path $(APP_PATH) diff --git a/test/fail.py b/test/fail.py old mode 100755 new mode 100644 index 07678e6..86999b7 --- a/test/fail.py +++ b/test/fail.py @@ -16,16 +16,12 @@ #* limitations under the License. #******************************************************************************** - from ledgerblue.comm import getDongle from ledgerblue.commException import CommException from binascii import hexlify from time import sleep - dongle = getDongle(True) - - ''' ################# GET PUBKEY ######################### @@ -43,8 +39,6 @@ # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode ''' - - ''' FAIL: @@ -72,26 +66,27 @@ ################# GET TRUSTED INPUT ######################### - packets = [ -"000000010100000002", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs -"b85175d43ddb3916230953ecd19db78be5a5054cb86acf34283ae06e3ab7bd8201000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) -"483045022100f508399521615aa61999a8ad25a3fee56565f0f760476d2699b86c93350c821d022010a2262fc46111eeb961a910e138ae1cdf2993bf37afea10c1dd45f0fa24dbfa01210355d934ca47cf6b34a73e5bcf128ee3322164f0ce494eccece2a8dbe1dedace76ffffff00", #witness + sequence -"f8a59eef9e5dbdbfafd235276fe585366728a2e96e716e77a9431698683e1ac600000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) -"4830450221008f43f80bb9b37908d4bfdb27aa1c0fddea616a9c04862de541ad33eaffb766c9022010c5989bb665cd17257c375a1ac22e09978ab50fa334f8232d526f98b1d589ce012102c4a3667333cbbdaf0c16d13cf18af81a2faea52d1f855819115bd028680c1ad3ffffff00", #witness + sequence -"02", # outputs -"f9dd1a000000000000001976a914977c43a6d5c17f7ec34ef2108ec54b773f009c4d88ac", #amount + script version + script -"5f310e000000000000001976a914e1a5c4a61d89d11f8a2f3c4204ad5c58024df60188ac", #amount + script version + script -"0000000000000000" #locktime + expiry + "000000010100000002", #input index (UTXO) (from 0, normal endian) + (begin tx streaming) version + number of inputs + "b85175d43ddb3916230953ecd19db78be5a5054cb86acf34283ae06e3ab7bd8201000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) + "483045022100f508399521615aa61999a8ad25a3fee56565f0f760476d2699b86c93350c821d022010a2262fc46111eeb961a910e138ae1cdf2993bf37afea10c1dd45f0fa24dbfa01210355d934ca47cf6b34a73e5bcf128ee3322164f0ce494eccece2a8dbe1dedace76ffffff00", #witness + sequence + "f8a59eef9e5dbdbfafd235276fe585366728a2e96e716e77a9431698683e1ac600000000006b", #wrong endian txid + outpout index + tree + witness size (could be deleted for decred) + "4830450221008f43f80bb9b37908d4bfdb27aa1c0fddea616a9c04862de541ad33eaffb766c9022010c5989bb665cd17257c375a1ac22e09978ab50fa334f8232d526f98b1d589ce012102c4a3667333cbbdaf0c16d13cf18af81a2faea52d1f855819115bd028680c1ad3ffffff00", #witness + sequence + "02", # outputs + "f9dd1a000000000000001976a914977c43a6d5c17f7ec34ef2108ec54b773f009c4d88ac", #amount + script version + script + "5f310e000000000000001976a914e1a5c4a61d89d11f8a2f3c4204ad5c58024df60188ac", #amount + script version + script + "0000000000000000" #locktime + expiry ] -packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] +packets[0] = "e0420000" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] result = dongle.exchange(bytearray.fromhex(packets[0])) for packet in packets[1:]: - packet = "e0428000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) + packet = "e0428000" + hexlify(bytes([int(len(packet) / 2) + ])).decode("utf-8") + packet + result = dongle.exchange(bytearray.fromhex(packet)) trusted_input = result @@ -102,78 +97,76 @@ expected = "334462e04608ca0441afe495cc5760c23914e553e0f0996c50095e39e13b1804010000004054890000000000" if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result[4:-8]).decode("utf-8"), expected)) - exit() - + print("Error:\nExpected:%s\nGot: %s\n" % + (hexlify(result[4:-8]).decode("utf-8"), expected)) + exit() ################# HASH INPUT START ######################### packets = [ -"0100000001",#version + number of input -#"0138320006a640c65057afdd582f4f086c6e6e8c160092e4c0d32b9faa9fa91b8feb1048379c020000002ac503f20100000085bdec7eae8ace3a01", -"01" + "%0.2X" % len(trusted_input) + hexlify(trusted_input).decode("utf-8") + "00" + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len -"76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff" # spend output script + sequence + "0100000001", #version + number of input + #"0138320006a640c65057afdd582f4f086c6e6e8c160092e4c0d32b9faa9fa91b8feb1048379c020000002ac503f20100000085bdec7eae8ace3a01", + "01" + "%0.2X" % len(trusted_input) + + hexlify(trusted_input).decode("utf-8") + "00" + + "19", # trusted input flag + [magic + 00 + rand(2) + input txid + input index + amount + HMAC] + tree + script len + "76a914b0809bbfc9c10ed4d70a0efe932e589ca11239d188acffffffff" # spend output script + sequence ] - - -packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] +packets[0] = "e0440000" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] result = dongle.exchange(bytearray.fromhex(packets[0])) for packet in packets[1:]: - packet = "e0448000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - + packet = "e0448000" + hexlify(bytes([int(len(packet) / 2) + ])).decode("utf-8") + packet + result = dongle.exchange(bytearray.fromhex(packet)) ################# HASH INPUT FINALIZE WITH CHANGE ######################### packets = [ -"058000002c8000002A800000000000000100000001", # change address bip44 path -"02ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac" #num output + amount + script version + new lock script + same for change addr + "058000002c8000002A800000000000000100000001", # change address bip44 path + "02ac211e000000000000001976a914fdeea9711e6c81027d677b2ceddf5c14d84977d288acc0cf6a000000000000001976a9149e882fd6fe9ff8da3f0309b15ff009f1e534719888ac" #num output + amount + script version + new lock script + same for change addr ] - -packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] +packets[0] = "e04aFF00" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] result = dongle.exchange(bytearray.fromhex(packets[0])) for packet in packets[1:-1]: - packet = "e04a0000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) - + packet = "e04a0000" + hexlify(bytes([int(len(packet) / 2) + ])).decode("utf-8") + packet + result = dongle.exchange(bytearray.fromhex(packet)) -packet = "e04a8000" + hexlify(bytes([int(len(packets[-1])/2)])).decode("utf-8") + packets[-1] +packet = "e04a8000" + hexlify(bytes([int(len(packets[-1]) / 2) + ])).decode("utf-8") + packets[-1] result = dongle.exchange(bytearray.fromhex(packet)) - - ################# HASH SIGN ######################### packets = [ -"058000002c8000002A800000000000000000000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type + "058000002c8000002A800000000000000000000001000000000000000001" #signing key path len + path + lock time + expiry + sighash type ] - -packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0])/2)])).decode("utf-8") + packets[0] +packets[0] = "e0480000" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] result = dongle.exchange(bytearray.fromhex(packets[0])) for packet in packets[1:]: - packet = "e0480000" + hexlify(bytes([int(len(packet)/2)])).decode("utf-8") + packet - result = dongle.exchange(bytearray.fromhex(packet)) + packet = "e0480000" + hexlify(bytes([int(len(packet) / 2) + ])).decode("utf-8") + packet + result = dongle.exchange(bytearray.fromhex(packet)) # 31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce 01 witness signature + sighash flag expected = "31450221008a38ca160729e7c381d50126eec970b5c82cb8ba0625498dd414681710da250a0220409b1c2fe867261d1624ad695be464c8a4c37a9e931d8687183697302221c9ce01" if expected not in hexlify(result).decode("utf-8"): - print("Error:\nExpected:%s\nGot: %s\n" % (hexlify(result).decode("utf-8"), expected)) - exit() - - - - + print("Error:\nExpected:%s\nGot: %s\n" % + (hexlify(result).decode("utf-8"), expected)) + exit() ''' APDU EXCHANGE RECAP: diff --git a/test/snapshots/nanos/test_1to2_get_pubkey/00000.png b/test/snapshots/nanos/test_1to2_get_pubkey/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..c29cb65dc7a27ccfee3e9f94ebe8b6a16e2c9450 GIT binary patch literal 489 zcmV92!LtM^!^XrqFFSC0lHGKwEi!9nm9 zDjfjeJbwLd+b1l>G*IglsNTi4&(YJ(k|Sv1ddL}qClBs1Fq=M`_y~YMw~8|g@!7R5 zJVrlgD?9ivVVu-dj}QN-V0tj!0Wm$2n7}1RP=b8a@%UbH5AG-T;7-!| zcjC1^mIlT0px4?FJ$Uk zap4{(6Z@MbELC{>Z>X}{yysvRGa`X#)e#^3HGr;6SS-lEe|z0xeV%xikXP(njw;h; zo+k&?nz|CPk;IZ$M)7%i-oNZ;1H-Fb|Mm#*cmX-+No06XBq&3;`>!eHkV@1XoY!6J zUxf1Px#tzF^x^t)_^ZGF*d?q+Ksk)N@c02uP9%>&UU^og>(g@Pzj(=C=?2XSe%EgOBlbR{XDK8JAn53 z(s&GQdP1+Jagji;Md*!RfZu2ZT`29|TDIN%w{U?*0Q)@Ah!#vAOad8=Oh5dDN(TTq zkINso-C;6A18Gz=O6VB?w%v!P8YwBraXu)ww9M1i7>G?NnKvb<_y~Z1w~CuK@>#)! zUuJy(*kZ-g3AYwxvet_lk%YNTxTjPW&hih(M^3(XOi#+)8Uul!v_8CP0VJ7Uwf+mi zn7XW=j9P;yQCa9o+>K0*p~Hih*U1cBM{lGS>dDIeB?(=zD6*v z!DxJZ1Pl$-^Ln&5&TZpVj`bD!ElNJz6_i_$NsbqvXEDXZ5&>Spo}V;wU`7SV?Q0000JK&k-#&AMe`>s8y^Y8CM+Iws z_r}c)bCy21ntveN+HsoO-J6g8yq&Kgu%GedZ+5qf8>THgrtPsLqtmjlKdVG((Pxg& zFa9(f4q;ujtl-~zAwB(IRJ?|?}_cO1t z>B$kCv@u-5wIyBtp+%_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_get_pubkey/00004.png b/test/snapshots/nanos/test_1to2_get_pubkey/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..4d13f81a58e4d37341dae89c3ed5deecc9a8d70e GIT binary patch literal 336 zcmV-W0k8gvP)2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000K?4J2QqX3 zXn7ePqhBDwvA-|J28LIrjF%tX0z{3v6!_gF&(SYH)S*7TN;1RxW-%}TLH9_+sttDO z-T32w&rL(!1@Vr`jm5G(8dd=Ruu#)JAN?l#rFLU`oQ(r?$33AC7s0}pw!fi~(9k^# zU9aci?pXN=I7A<-f!Mw2untnw9MivqZYw}c5&)gweYhbTnv#2#t$0X2wST7_1F;LR zw?>Da2SkSfG>qWq1mej-6nW@2l+Z=0om5jdB%3o3Qx19_LNUlTqF4R_1Iaj%@^2O= z@;n%h1N>H$2;%-~Dvx1!0LtkT-;cq73rgisOElFtPbcL{d3TfNQvm<~003s>1*i4o Uje8$F8UO$Q07*qoM6N<$g5rpv%m4rY literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_hash_input_finalize/00001.png b/test/snapshots/nanos/test_1to2_hash_input_finalize/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..c83207dc6df91b5b66a91d4ac82f4c6e646818fe GIT binary patch literal 319 zcmV-F0l@x=P)S`kB- z?T0gSwiA$+pGgl8{sL{li}LtKpA7&~ka;8ABpymQ*%kd&Qcn>=2qA=!P*zfUl}s2S R3e5lj002ovPDHLkV1iKUh>!pP literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_hash_input_finalize/00002.png b/test/snapshots/nanos/test_1to2_hash_input_finalize/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..5bb375849df8ff5090be64da6cc75952f7fab073 GIT binary patch literal 512 zcmV+b0{{JqP)q9lLD<~Oq);CL9H$@t zhOz?yoX55Aw%uVdID>0^AQM($fh8j`B?UQdqRKQm^JE`Gp9SYyA7(@V0Brm98OLAx z*c@uptq;Q^pjuKgO>zddQPXf`2mM1hPuf(EB%JM%MNYooFfYp88V$lFtq*TF&$U;xz+sGTy%$>}x5&W?%^{h^W)sV7}hTnV;#0peY`KLTZ*~%%e z*U+*YWvwrC6Yg*{_b}$FN~3_DN50XrqN5NiYnD>Ep_PjqSXi#)l%tlE;3ad_xTsHG zC7h{+YSSHMLclphSxb|uDoIKz@@@(kr&8#1Kr?$*YAF;V$j#mrZYJdZ6Vc&-<`Yba zYvocqEn@JQZreJd`!@8}4Vr;`=r!sKpo;)`7vDOBRYS0Q$iR}bkjtx{O2c1-%i;|r z@{r$hiOV}nuOayL=KwtSuLu&8(|z;l6$k_ZOXCCX09Kb_1emA*0000X literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_hash_input_finalize/00003.png b/test/snapshots/nanos/test_1to2_hash_input_finalize/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..23725f0a1a0b426177d1161d12062ae9ef511f19 GIT binary patch literal 499 zcmV^ZpNi|s&L z=MLjG%Jh_0i*RrNl0<2Z55OndfQZrWMY8SgkI4ni0QSB^hyrF$CSwLjkI&;LR678` zd0gvp+b2wh?%7-p2p{ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_hash_input_finalize/00004.png b/test/snapshots/nanos/test_1to2_hash_input_finalize/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..eb415e41a802b4041aa9bbafe02a4829cf8f4f92 GIT binary patch literal 332 zcmV-S0ki&zP)1xvusBW%UXppIlu*eUgJVw!0001m?H0P$Iq@h@$tAJ)2|XWP)S2#oB{?w)_z&@gT~z51yD e000004%h%MG_5lv1iobe0000j~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_hash_input_finalize/00006.png b/test/snapshots/nanos/test_1to2_hash_input_finalize/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..4d13f81a58e4d37341dae89c3ed5deecc9a8d70e GIT binary patch literal 336 zcmV-W0k8gvP)2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000khDFkMn_k)udSP9~-uDS4?Ood6>rpM2c#!j=|+T%Hf~ z2EkGIN2CM_Kn;fvm^q+K%{fV85$g28t(yT56g9a~xt`{8Amw3V<++0cBAPk@15mz+ zsZseHWERy&(7t_to#5BpuX@7+t<;KGUXcOmj`zFI9O;}^X2~ciBLOLtSV2{nw0M4A z`yN2fgP+`8Kw%_|s=DCYH{B6beLfloK2&7@A0rQVu_7<^lE0L%`c}7~VN^s<`Qf9B z(Og06dL4QUV2gA$fP5o0c+Rn}=!WLDyC}2PFBolSn4CQ7b~N83djOq7L|ud%HtsKb zjp%Cu)5uIEk!GP-f7ZJNm7ZX-o|i~7yh&?sDN@#RK);l~)I8%7vC{Vdva2ynGivvb zVkHN-p6egJvqDxnf-Y;I{KQ9+In7Y4qFrhjhG7_nVbt;ut*q)yoG44I00000NkvXX Hu0mjfCPL6V literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize/00001.png b/test/snapshots/nanos/test_1to2_warning_finalize/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..9d6a5def4f3f96b4715baddbea5661de00c802f2 GIT binary patch literal 507 zcmVA@L7wehgP!5zKnA%k|X1X76-i9{liIEmNu^H)}uh3{KUts`O# zEZ(NtiEzAJ2l!60Z-_BFkp@EkIW76dwkwOpp+c=)JQn2&iAWeHv(?nF?SHn?*Cy@W z0P4y6U!3~Y$VKPJ5JOU=naaHmUtC!$$yHC*!IBq%QS|j+Vn6`3}s`^!uRjhsY4nx+P!n*%UwhcRy zFFqohm!8i*+<_T_g7d-2i>LqHQ71IV3JsL(t9|C1Lh<~*!Q2#i2H(WeRp{TNvB{_3 z9$?2Wsm^4v9w+qj)Kv9eQB8xAKj6)!uv%``R6Fx_wf(LK<3PMKhjEd!L1cZNrcO4q zD^xs93#aw}3;0fhdEP)J6G97?*#7VAVh2<}1Lg_=0002E$a~p7N#YjSw>*SAqGABm zb_-eX(hu!BCC4IY6(PSa&-@Z+MwlE*+T6ueNF{+pQj9EYRac1f_RLmS8xr>9FFZ9= zD10$7M5kzCIhx*pIs+Qf)TL8%4GZ9V*(DauKZ_i?>i_~*d06stkxw)?RCPnJYqa|z zgh{)AdCQG+|LT0#?gwoKtX;0Ltu-E1v07@R?E0+gs94MHt%hhbFXXIU%OmOdBeJC{ zo*JNZ;1?6g$f;C!Pyc6=Cv=I23lzOq%Yz4n@qFB11_fu(6W3Mf@$5G_GHU02xbbf# zpZMS2IzpNbn8E6sFwj9tkbjN}&J(hGEY9AXfiWTiS+X6d2#>%002ovPDHLkV1f^Aqx=8> literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize/00003.png b/test/snapshots/nanos/test_1to2_warning_finalize/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..67a35f24cca0b8feb7f61c32bc0d3f54b8c0a078 GIT binary patch literal 494 zcmVQ$0!msdilQjKmD|Po_wDcc_VCJkBzwDp zkxc1a(~^#TdkqmT&Qmcc6V`6>bBfj}h|ZxcTdk4whF2oAfV?5YZ@I^i4#}$DH}TP3 z7;6S#pyX>0WpE=r!eSglM(kO<*5K3mpBx^bt!v}kM46Mqh^891IHNpsi_iqvi6xMB zp1#RH!_&#p5*r1_s9B)!H4uV~urNrk-Me0lfmapR(yMng2WaVTWG5$Pwx?TYlPb#a zM%*$Bo(TYdIBKo!8#@R1-{;?qZ%^WqZS{1eXer$31HT&V2WzbV;lw-?oPEI#WQ~>u zN`(%?I#y1=C-FAdI|RixTUrt>Y}8QSWkIs=%MY9!n8;~C(cCo$hcM%W%F)K2=e+Gu z_PTD6feDyWioi9(CLQs_f|pi)Am<};5aTUkhii$RgpCo~PdPjzX>~`VbB|J9wzI3P zOUO|T#l&ijPPZfGPLQthO+YW?k4kS9_G1{0rT_o{ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize/00004.png b/test/snapshots/nanos/test_1to2_warning_finalize/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a5819d8f6944f4d516e7a78b5f45b293249edd GIT binary patch literal 333 zcmV-T0kZyyP)?phMX)+}BF5FlZA%qY@2>F@wkn=znF~$R3!2if5 zePI;?RQ+v-)-g;f16m1_R((lkK*4#CS$#=nfJ&^QCs$uYHgo~w#1u-azEpO={AUR# zcV_hi^Q*5UJo0~HwcnEqs*i^r;GqY2=m8fNfl7lMu;F)Fm^{|BHe#Az*AZSJ9? zZ-NK{N-#kq54QtsSjR@c<;yH;jl@KnKz9WlL8?VR-1~!WHTU4{&zvBI=A$agqDrB6 f!0n*{>Jl*`Zbd+ijdF40ySvhiBDQR<~oswFJs$Kkd=61KU`*A~1 ztW-SJFRyAZxD9N;WZv2V^wG`s(M7QVTo^sInkhk%?AK0}7r`lQWT`UYAD7B%WwY&Q zwPVq0_toV9qT9~8YZy?wkm{-Z_-xcg8BReuWKK^?GYOoTn=*ef!#sd1L_vdn-d5ZN zamy`E#pDV_Gt{z-FM3kU(L|o|wj?!d_|pQnp@iz4BDfIF-fegQj-iv8x&b+JSPJ@! paqthxb6F+?A>RT300013;sZN2%*e>R7rFod002ovPDHLkV1iNOmAC)^ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_1/00001.png b/test/snapshots/nanos/test_1to2_warning_finalize_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..8f60ffbf9ab55968fd588231539c8630405cc8b1 GIT binary patch literal 365 zcmV-z0h0cSP)g;3u?C=vHKJ$n7jjnvW4IrXyx8^&24#I?>$#g#m;{YDn z=OBOs^2|y9DAdf2Vp^sr{tKFfC)W_3xfKtScSXbyic|5{6fM?^rGZRY;JWJ=?_T0N^-3zj^XY z8@pX?x%OeY2cRt_)g)t39jS^d8SF_oPpU4D6}Z|Yn^eBvaBph3HWYzdY9HQY07>Sq z+J7M!RfqN$BW&;_A__f;ZzUhha4x)%J(>zKRG14q$-^5u0J4piIL4Rd+DQ8l-d)8;!bB= z33VEE3LCsPVYVj&V%%UOTNx12!;m~Q_4+#Wdh9iTV-b&Mc>9q@oR;*HKtB;0Apqbs zfU!?P8EUz%DH^y@x)*Xg3#Tj@oGG)T8#*dnYy;YqHS~Zr4`4GV>v4#pN>f4iJ>6JUIZVM5)aWz&E=C5vSi<$uuASS!~b@VDAHkC}93%a%O<^_&7eP)&T(4 zWm}KaJYX_(2lvE48WOsfN;0`*3mUkHkZan`(_##k2hY?dke>knFwNVQXTOiJl4=k0 zJ^)O)=9L6TE^D=@5Lt-5gr!a;<5KTe@REPNd%}|%?hV7>E4>d-3V>$wt=@kijH}E0 z7gI5~liG#ucT*8+{A3djydqSG+Fc9ZsU=Wb*absID5ky z_xGZUn&!fa**68NJ*pJZPo6z1{c#>u@}x@XIM&zFS$MQ5cFdP<)Jg{Vt3X{B%2oz@ z_n9`OdugZvv;IPmldL06jAM`WN*mY<22^FEvO$JO5H?G5h0cN_EdaDjR>%Y^qoqX} z_C89fRh6dwNQ=zkzAs`ktXVLMz&?mgb+dqA*R_k+c)nb#&~!a@IBbn z2d)x8w7;ybbqqrlK&!*h+BdQQ0$B#k_Khrns5nX|w{K>PcLC#+U5M7cRh|I+vqYww z%l?U8eESi?BmbLb*`)WwNJX{m{~2ZAiMo&{*V%^|kzR2I@A>j0z(x_}jNunQffVr5 zyMR7YW#QF#bR{fi0Ry~6Bh7+ZL!MIB@k+cdFRGt)1*`>`*|Jv5rW~vsw-=<&6Txdi zGn!!j*Zsge0qJBvo%@$gdseDI#sjkl^tAQB%qE0000|)v literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_2/00000.png b/test/snapshots/nanos/test_1to2_warning_finalize_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..589be36c46221e425aa52ee77b0b297de1ac347e GIT binary patch literal 350 zcmV-k0iphhP)MhEU$r6!1@JcOnM001B=%jgB9v~Qp1WmSr2!F|)r z5So4aIRJ(D{pgf3QlmY9v)QuT^7iN`)e-V)S?OoTnPsKqnVapB)I?P6;(M?>HwT*^ z3xaB;>ZQJUR7b&W-~a~mv`%1;Zn3W}h6CWj=%wAv35sMtIaU4%PN|TkjtT#~R8gy2 zZ9{7ui#EHjEe8yc w-JgKwzZ~8%x1)PO?A`HA6aWAK005-)0*1iK=SX*9ApigX07*qoM6N<$g7gEPN&o-= literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_2/00001.png b/test/snapshots/nanos/test_1to2_warning_finalize_2/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..c83207dc6df91b5b66a91d4ac82f4c6e646818fe GIT binary patch literal 319 zcmV-F0l@x=P)S`kB- z?T0gSwiA$+pGgl8{sL{li}LtKpA7&~ka;8ABpymQ*%kd&Qcn>=2qA=!P*zfUl}s2S R3e5lj002ovPDHLkV1iKUh>!pP literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_2/00002.png b/test/snapshots/nanos/test_1to2_warning_finalize_2/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..5bb375849df8ff5090be64da6cc75952f7fab073 GIT binary patch literal 512 zcmV+b0{{JqP)q9lLD<~Oq);CL9H$@t zhOz?yoX55Aw%uVdID>0^AQM($fh8j`B?UQdqRKQm^JE`Gp9SYyA7(@V0Brm98OLAx z*c@uptq;Q^pjuKgO>zddQPXf`2mM1hPuf(EB%JM%MNYooFfYp88V$lFtq*TF&$U;xz+sGTy%$>}x5&W?%^{h^W)sV7}hTnV;#0peY`KLTZ*~%%e z*U+*YWvwrC6Yg*{_b}$FN~3_DN50XrqN5NiYnD>Ep_PjqSXi#)l%tlE;3ad_xTsHG zC7h{+YSSHMLclphSxb|uDoIKz@@@(kr&8#1Kr?$*YAF;V$j#mrZYJdZ6Vc&-<`Yba zYvocqEn@JQZreJd`!@8}4Vr;`=r!sKpo;)`7vDOBRYS0Q$iR}bkjtx{O2c1-%i;|r z@{r$hiOV}nuOayL=KwtSuLu&8(|z;l6$k_ZOXCCX09Kb_1emA*0000X literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_2/00003.png b/test/snapshots/nanos/test_1to2_warning_finalize_2/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..23725f0a1a0b426177d1161d12062ae9ef511f19 GIT binary patch literal 499 zcmV^ZpNi|s&L z=MLjG%Jh_0i*RrNl0<2Z55OndfQZrWMY8SgkI4ni0QSB^hyrF$CSwLjkI&;LR678` zd0gvp+b2wh?%7-p2p{ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_2/00004.png b/test/snapshots/nanos/test_1to2_warning_finalize_2/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..1e284f082ac82ce25a1a8f68870b8152aa91a8ec GIT binary patch literal 324 zcmV-K0lWT*P)ktXVLMz&?mgb+dqA*R_k+c)nb#&~!a@IBbn z2d)x8w7;ybbqqrlK&!*h+BdQQ0$B#k_Khrns5nX|w{K>PcLC#+U5M7cRh|I+vqYww z%l?U8eESi?BmbLb*`)WwNJX{m{~2ZAiMo&{*V%^|kzR2I@A>j0z(x_}jNunQffVr5 zyMR7YW#QF#bR{fi0Ry~6Bh7+ZL!MIB@k+cdFRGt)1*`>`*|Jv5rW~vsw-=<&6Txdi zGn!!j*Zsge0qJBvo%@$gdseDI#sjkl^tAQB%qE0000|)v literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_3/00000.png b/test/snapshots/nanos/test_1to2_warning_finalize_3/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..8d84cc70fea8013b7e8b25c0982ce142fa103d5c GIT binary patch literal 374 zcmV-+0g3*JP)K?4J2QqX3 zXn7ePqhBDwvA-|J28LIrjF%tX0z{3v6!_gF&(SYH)S*7TN;1RxW-%}TLH9_+sttDO z-T32w&rL(!1@Vr`jm5G(8dd=Ruu#)JAN?l#rFLU`oQ(r?$33AC7s0}pw!fi~(9k^# zU9aci?pXN=I7A<-f!Mw2untnw9MivqZYw}c5&)gweYhbTnv#2#t$0X2wST7_1F;LR zw?>Da2SkSfG>qWq1mej-6nW@2l+Z=0om5jdB%3o3Qx19_LNUlTqF4R_1Iaj%@^2O= z@;n%h1N>H$2;%-~Dvx1!0LtkT-;cq73rgisOElFtPbcL{d3TfNQvm<~003s>1*i4o Uje8$F8UO$Q07*qoM6N<$g5rpv%m4rY literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_3/00001.png b/test/snapshots/nanos/test_1to2_warning_finalize_3/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..eb415e41a802b4041aa9bbafe02a4829cf8f4f92 GIT binary patch literal 332 zcmV-S0ki&zP)1xvusBW%UXppIlu*eUgJVw!0001m?H0P$Iq@h@$tAJ)2|XWP)S2#oB{?w)_z&@gT~z51yD e000004%h%MG_5lv1iobe0000j~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00000.png b/test/snapshots/nanos/test_2to2_finalize_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..8d84cc70fea8013b7e8b25c0982ce142fa103d5c GIT binary patch literal 374 zcmV-+0g3*JP)K?4J2QqX3 zXn7ePqhBDwvA-|J28LIrjF%tX0z{3v6!_gF&(SYH)S*7TN;1RxW-%}TLH9_+sttDO z-T32w&rL(!1@Vr`jm5G(8dd=Ruu#)JAN?l#rFLU`oQ(r?$33AC7s0}pw!fi~(9k^# zU9aci?pXN=I7A<-f!Mw2untnw9MivqZYw}c5&)gweYhbTnv#2#t$0X2wST7_1F;LR zw?>Da2SkSfG>qWq1mej-6nW@2l+Z=0om5jdB%3o3Qx19_LNUlTqF4R_1Iaj%@^2O= z@;n%h1N>H$2;%-~Dvx1!0LtkT-;cq73rgisOElFtPbcL{d3TfNQvm<~003s>1*i4o Uje8$F8UO$Q07*qoM6N<$g5rpv%m4rY literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00001.png b/test/snapshots/nanos/test_2to2_finalize_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..2541d4aca2b5ac87059a824402b1ecf51c5d1d9a GIT binary patch literal 329 zcmV-P0k-~$P)lLqM4&eP0TT8*nV2}vu8JZN0000G&-D`BgUa01ck>{P+2`mE z*l>;7@_cN|_yK<-%R@V~HoJdc9XSKkvMhZ6GL%zv2Z)G`RzA{ekY))grh6xi0di%p zK>`DKwgFSf(xhB@M#G2B0?+d7-`orpQp=4Ml3G?+iSM1glUaYmu8$?YT1> zEVnk4R#r!C?aiu?ZK$)na|Q!=u0~ErD^n!@omQnu3gyTJspJ|d|02OjID~$Xj<$Jk z2B_(W&)Vs6CDen&OOQ%i!pH1yNo>H2@OYqW1F;QtX6rUoy?q>hv2G~U_K!8600000 b0QSNSuY;XG+N&t>00000NkvXXu0mjfW}u9G literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00002.png b/test/snapshots/nanos/test_2to2_finalize_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..599f89fcb82a4fbf5805ade558df62ce12732706 GIT binary patch literal 521 zcmV+k0`~ohP)1A3GVW$C_CE9unH$&prdH@yB?c1RK{&INSiN70!#aI@FnWuPyGTsC~ zroD#{!g+k-ZrcY;rs$yBA;`SQwvVwBW=aYgIG-ekQ0AdE4$P-(W4{B!Us%~WC5hR& zA>4`a4&WO+N<<$O9d}j04`CX#XdZw3hRyVx*r}j-Qp3Gb=Lh3_Z#*}&d}hcoQ}v`Yn5nayz==Q(@;pE8H!{qoIg00000 LNkvXXu0mjfvUl+8 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00003.png b/test/snapshots/nanos/test_2to2_finalize_1/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..10ddd37c9ab292740d3585c3b1a9f4183df44a65 GIT binary patch literal 503 zcmVl4w^SG*i>DPblnwXBdyxVH&go%+I6{k!v$lkX?D2NiCOiojP|pJsA^C-be= zpAf~=Y5j*uAB-edp^~pQ({ET%VZso>Y zQ4?)4kMIN@xq;QS)fWNpQ1a!AHM#WZ!V(opHA(5; zo|~{Q9xO|$-a7r_g^dl>xm&$ZZv}D5IK=;xl*{i2ZP9}{pt_^72hLlWpKf%p_QQ6`IBK>Pw?>RUGrXNyTbxq} t3LMQNA7m1nasP@KMehwiNs{FM@B>aAd*C^b)E@u<002ovPDHLkV1oPF>m2|9 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00004.png b/test/snapshots/nanos/test_2to2_finalize_1/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..6733df10d50e3a3878eac79c7fe6cd4d9cb1a990 GIT binary patch literal 319 zcmV-F0l@x=P)2qOP8Ps004k3+j`EGc>YTEZQVc72SRV# zWeme_FX1gQUR=PDCE>L%z|%UxA%(hoi(5|rgq`pNM88)URl!P%8jc{9q9kTJ9;VSn zM7DMBN4GTCOje+53b%Z%#4j)EwWrGnYPcUYTm0nlHI_irxv@V1@@^|TQB=?NZQ+YJ z+wfsCdW(|GdzDc|sCx;ANlSu9*Kf}6^v(&YH`QE?Ou$>JFEbS&74xp@Pe?>+)b9*6 z7ztBoB!BuIo&@BD7G&@Bz?{z;*7W}kbJOK62#%ouP|Yo-KPLbH00006@B%Qm#Et?K RJ`w-`002ovPDHLkV1lhshCu)T literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00005.png b/test/snapshots/nanos/test_2to2_finalize_1/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..fba60e7c37d62ce28ab99e1b114037ca7eaa9f34 GIT binary patch literal 342 zcmV-c0jd6pP)a7(5lVoMVN3L0001Gcy>)3!S?TfP;244#&~HPFc{~J`(Tk{ zD9^joD&D6Et+~AE9v}HrfzkIh%wNa{vGU literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00006.png b/test/snapshots/nanos/test_2to2_finalize_1/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..1c9156c31edf73cb072eaebf2db3fbe1ba5c612b GIT binary patch literal 414 zcmV;P0b%}$P)j~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_2to2_finalize_1/00007.png b/test/snapshots/nanos/test_2to2_finalize_1/00007.png new file mode 100644 index 0000000000000000000000000000000000000000..4d13f81a58e4d37341dae89c3ed5deecc9a8d70e GIT binary patch literal 336 zcmV-W0k8gvP)2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000m1gYoarBO3LH$euV2HeiC{**okfHIi+m$sv2p+{O|Q}I5aNh^Ys5dP#v zj%1qABdJ+S6K!y2Hbl8uvs5Q~cSHZe-9%(GG&6lVhU>>5GXsQK^2D%BBCpwrIq!n_ zbF$#pv0JKROAs&1vS|{M6`m6<_23d_XsOOAL5k@8zo4r@s|o-B(!2ofEx#wWs1tqw O0000Ofd$C9kGroVISJ&{ zNuP1^%)>2vC#j{oxmjh{;KEI~+N|*2l{UAtV;E${a-NWa%1K%_VS-sTe>9doQ?wu& z1SDVLFfsp>W+yDkRpq=Ez$Ni?J8dem0k8V@O$)E5fO6pF?|vqqFz*x6T!eW&b*i@| z*5FFMAPYU1&xgDTw?XekJbB@cmFT!CKtT^jbgF5&Brfkb9t}~~UFP71Ow|a|grKRb zSq7%?V504@BJP>9yTr>FUI1eWL1#XZuYLL?l%bhs-KG_q+Oy~` zLn~jnncDm}Cs?ZPBDi`WxReiqAP9mW2#9_G%>Ae8b$O}^00000NkvXXu0mjfdLQV+ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_decred_sign_message/00002.png b/test/snapshots/nanos/test_decred_sign_message/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..ae618de3dd68103d1e18e7e9551b0d4c6b5d5a1c GIT binary patch literal 502 zcmVA^`{l0)arlf$N0ptVr%OW_T~GP4l9S zlZ4j#jrs9*_+L2QpO5QgzS&wQ<}3higk+Yn$V#MM%5b_)+NRZa>wpJPDY74Ik;?6= z3W-vy*kCcwIEvI=#^e)_OY)6Yoai>4-p0*D!SYYPS^(%;faCp{Cmp_!APMBuncGd7 zhidjtQldMr9=%JS_W|J5)7b}HFt$h=&!A>~P>RXkhba`4PttM;gUYISXuNl(#O&4X zX)N}xX89*qJ77sxh4YdDOYCVLwAzt0c$L-9i^(1ZjRTkOeFVNR_c3WKn0bBcRJTQ} z!Ad-Ug}xYnoqRCW)q9v`T2NR#cXbJy^O5Azqpz@8v5ji0&cc#Gl2ox66Q^2IE)9vD zYQjfKFjNyY#_WwT=}f1z@S%0(+8G z`q{!7Gc*I5W7h>R1_C(|_j`n0hMC@n#yen#Xf>rvF==XK8!sk%ADA%If*ZonYPc!M sS!Oqep?Zkv`hgk<1OkCTAP`XT3xw2kkn_rP5C8xG07*qoM6N<$g1t-W;{X5v literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_decred_sign_message/00003.png b/test/snapshots/nanos/test_decred_sign_message/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..75b40980f5f9ac54c6bd527044bc220bea688d7f GIT binary patch literal 417 zcmV;S0bc%zP)O41|MY-~WMos0U^+hM$H)yJ^jLVgLmH`}avix??V4213&qcx!GHx3QCJGfavC*ld$H;~ z2^$tPB9qB=tp~aTlJ0y5Y->SNO-&K=;W_6FPzZYa+`$)f?tb?=qCVr^=qrl)z^^4fQUMsr)V-*=eZq|W8ms{!GsF3LGK>5 zN37FkN91Gs;L5eH9M0yBoIj=Of2U1lk76kqCmzH3ovPTm)>M1br9QP$t_7Wpi%E!F zrransuWOOi%UeZZ{M|DQIvJ-lldf)PO}j9VjB77jCGBjs7|s%C3sRy{Z8wlpB0U?Z z1;sN^X)o>0jq^G0V=oMkMug4SE%qiB^jy&IfNQAzOXE0>^WS^`>4N1ffC@i-00000 LNkvXXu0mjftcAH_ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_decred_sign_message/00004.png b/test/snapshots/nanos/test_decred_sign_message/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..4d13f81a58e4d37341dae89c3ed5deecc9a8d70e GIT binary patch literal 336 zcmV-W0k8gvP)2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000KXnwA0p00000z-Mxv=Xsv~j|};@ z<2&1cQeF9Pd^*HWwgD<)Jj7}^j^i3Xj)TbfN3uw+0OC+m4a7C#AW>3fL`Rdkd}Ke5 zr~u+DXYR)|v>w+Yx|94KP;O|dM?>j3J-7E{2B1E9yA@n}Iv4ijsUh>s{il@jmAJOO zCy0GgYo}U9KfehB00000fEUhJ46&{rW5oWnE8iY{yQYfTY-2p~;?hpbzo3K>@?KGak^BXkTk(?LKqE&|R zS(lxf_i*{z=ho)2tuwtbcl!u2Q1P4q>R(qjQ%C6 zhAttr6`fy~BgQQe*3K-GEYYSNqqNg#S2%tU(<0Avq$s})sUHPSMq~lvM5&*H}4o(j$uG^A&h zJ-Ngz8K{6&#lC;j*u&`7G==y#qs_^kPHHl j3<3ZE00000z~}J`zqCQ$s2e_`00000NkvXXu0mjf@^wc| literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_1to2_get_pubkey/00001.png b/test/snapshots/nanosp/test_1to2_get_pubkey/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_1to2_hash_input_finalize/00000.png b/test/snapshots/nanosp/test_1to2_hash_input_finalize/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..487ea10fcfeb2f3e6b79239459672251d49addd7 GIT binary patch literal 414 zcmV;P0b%}$P)vpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*a0XUzZionjl!99%>gfx6_pLqkn}X)*nAi*M-g;QqVG?!@K$ z>tArs2)Y{N#T%@BrN}zrM{n-abC3N}`MZVeneTXPk zo!LX$lPb;-AUs zazJ;lnSWz``D%yVHCsaePCHz%aOcMDk5`rXe-+u>yWk<$-CW_bS?5DtJwGa#eVNcW zb33zG#q*gzvm(tN-@CG(dB^VAXB+h2JxG`MH)$ucSziCQwb$Gu}~gecV$*KQ# zeD8K3y+ZkKV%o&dZU?HE`7mcg&iO9SIg2`Y$u2g}01;3z8$@W#LSf`p#|*S+t4p5e zh#4S)1&;kb3uVM>8GVxddq7&Sspf(d1%2<{vois&Coh+RdrjAsk#XwOIdlCEh3`);bB1GpXS%#2lB}ayv7XL1)sJ@o{<| z660Q`@BW^-QfkpcuM$pMXOw_ON>f_i(7yS0h7u62p297}A#J=nyQTx>*sRrmlKupQ zI~XYGI1EOlBWK{Soye#f>I^8bg5UNK&2k-b2ACt-AH{fpbQ7H(b7J|c&`6GJ9xftS zOZUE-n9_TP5x>dwm{bj(@KM6J4-*qG{XL!6;|bB9Leqm>f2{Mz=^7{^YdCrp`u7Au zW)7C3!|SP`rhFKlQxkAU>mU@GYCa$(p#&>rkD9P*`ZE-SCLIyfO-I~lt>CMzPTNrR z#D!JALLfz$>Q!rQYpNOY=0N-@?97^E_!9|*DvjMtQ=b+TeneG*)bRyQ(1_!J?nRU| zJ&{94+qK_@F4CxdRayKLD*H|stwJoaod^Ok?rz^LwoFuMnmT=;7abWLC?t8yzYSfH zgTZ03lw72vOg{}1?Nj`$Cm vx8T72h7dvsA%qY@2qAK;A6FlvHV~3(j}{OW?S(s1?pnB{C5rCfyJx7E$&#;rE;#glp#5O z=65YeM!z@r7hPKx`=&0}x&JC-&&sT`&k7Zl%ue4u>KuC~tSQ~0eD-e_mDBbL@!VSb zg`6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O00007f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_1to2_warning_finalize/00000.png b/test/snapshots/nanosp/test_1to2_warning_finalize/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..d08297ed46739c96729072ae4af65cfdfe409c8a GIT binary patch literal 529 zcmV+s0`C2ZP)VJiL^(Q~-=mUqmg~>)&k#hN0kDkLFpoI= zx41Jv`8uNOcjBFbHjbe$;WI8`000000K=(oFrD{+T2V@Ae|Ymq{)mz}^qHD-mY;Nn zB2r34i!6UOkA$1bNZq-06IMe&8D~DPyGp$^m6#g#p`=nV=F~j4!C7N1)@rYZG7p{) z#+l74v&0Odr9WCqq<~5Qn9Y{6^V9}sjjb8qG5e+2KUY7#T9Yc6Z~b~6x51RJNB4uM zK{K`k3U@XMIRO1mtSj}~&{3mbvod3BKH#{`oOBc3VWX>= z+5xRAek*>b>6?;w#CPW+}E8Ua|@S0000000000zzlu?TmF3^ T7S#2+00000NkvXXu0mjf{Wk1G literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_1to2_warning_finalize/00001.png b/test/snapshots/nanosp/test_1to2_warning_finalize/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..936cbee44304c692fdafc753aa00441a9272af53 GIT binary patch literal 554 zcmV+_0@eMAP)G%00013&X=k8<2d5jdmklX zd~?=>`eWz%LAefW3D~dz9pcJJmqjWGLhpS?bLb(PtFIp=SsAhbF6Z0A>5%MZ{0sLt zHK7I_^Q^74iloe#`b?D{+=6tfDVwzwon#AZJNpZeK7e`>UG1T^o6(LvE$Ad^mzZr4 zciR*g79c)i0Yy#pocUBHs=jqw@8|8y;-+M&5i@o3gg&wbeG<06gfFMsG!&D&wSEAA zN22WWTI1@~a&J?P-_S{~R(Gh?sl~gi8n(=@+=F%IXeCAWaDGsxcsR?oF;{i^1(?`| z9*s|9rM$J}Xn9a<`#N@;93|#6w(7SaJ^N>(SxI~_Lsan#T^eNPu1n3-TgNuT_CV(C z+9m8%=y!Ldxf5M5m z43bO@Oexd*uoE%YI9|^rV94S->P)NfbY7VUzCM>2GBlFY8xaofah`MwLvliR7{^IuOkEi004j;Nax1o zLaX;BK2JGwT-->(ntzGEC`4TpkzUwfF4Gnm82jxC@VdLe5y_XsrQpEz})ru&D0f-(ohXrF6j&Io=Rk z#oC#zh0hkzT9U!I|L+8|dS6(z2cM(5mcW1uw?vm+6Ad+Yw(_B0gy+$TJY`8!$=V4T zgA2e&2Y2L==5DT|l=lH30){^T005AaU)@e0{yUmS8Oe|D3)Oo83~|B|N4bUJ%!NFE z4$y~BFLFtKShN!^6=Fpdv2f->j_+CSB^IqT;|iK3;moycXMkD6oy^o?vcu1G&o4oO zK(umX{h1PYC)*i-{MDZ3Q%6Ru-)(e8M#-Se-4!|1j!jMc=4!j z_CJRO);kNf|C#^xTYZvZt?H%gi`lBKIP^;~T)*|9>>tm^$s6J??VLTmiitVa@RZl# z9D}7HW~IBg#_v|Osdspo)b@#I##$}$!vTL1erwOq|6RGGG~%xIOYz59T*k-q6J81a z$=e)pd!KrK?JqHvo`lxakeiYh%(DN_TKY9re^&30zAaAgrtV<9s?#_7_s4|tE$2+UT~i!DCi)dVeekXbfGQn;e2~0fAOicmauuP0002Mzj&=KKtD4J$KLye zCAmVf0^-oe6stk60z&lTa2HQXc&{!%rzFsFaaUz#@%^X$QG#j@z%sRFuGsvYZVyOe ztr+@^-Ym#54ZVqHEW`i+0D$S{E*LG+oje>5E!vID`fC@rVwOa_yP*usci2kU%!B_NjoM%I`cQE8xLXmr?Tj{%7E&qO)?n_k!~17dJ04(N+iTeNYvWx1c8xtAH@l);a;EJNPI@g;)=W jG2Q|I00000065_bLe?2BGhBsU00000NkvXXu0mjf6RxS% literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_1to2_warning_finalize_1/00001.png b/test/snapshots/nanosp/test_1to2_warning_finalize_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..a6c5bdbf3c27d8adcb839d4830f2e9221390b6a3 GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=ltba4!+nDh2#bkSi29*4lK zm*;Nyuex!1ox$OZBd5!lf@W9mo0GsH=$N1c(p9r&PVu>$yT$qT?X^}=3UaQ`;d#{a zy}z8jt>~QQQlVv4f$LuL-YqZDz1)}Sb^qDXdbSzyi|Qhimg}F%-CFWfa97n{Kh2+R z@k%@nh1z1dN1C5ZW?!^q!G7t3;+E$b=FYnP#O~5L(eFN=B05BtO#ZZ1>u%_lSOc}I z_GQl)85n;2x^-pU&3i9v7wTo57uscg;^ac#=q)wr{|c+bcfW~0u{`YvT z7n$0f*Bs7g;O5WvTTWa??#Q-(Q{poJoD#lsyR|~7Eb)+S=f7)>oaGYRAFp<^%kMB^ z5cmHkzg_3-p$qFSRc*bnb=x!5b`g`#P5*YkTC(KCP2T>wjQKJj-pQ?N`4M)=u-@>M z-!|9Dc`i5H^$tl}hX0d3tRVb1*=nKMuXaPWc_*Cai8-e6Y*X3;3^QbKz-<4N{~`fL SSHG7B346NwxvX$hB`1VW9}+O+Q)>2Ex%?cOt!P3036|1_nptO`epsnPjJc=61k|C2CLfWc zD8|WS{r}fazXBX_ImxAm+p`PHe~KMYaANuUmi&-sH8bgF{~&LXDTh(%05wUf zZmAPR&5CrrCeu$ZHtjMsealo$nRPXE)^hPNuz>V>xC5U7R<I!T@(?#dOh3yFSl;sKFVwC^@%Bsu-mCEsVR9dU zA?B|_AWslv^ueXb@WwCYty2=yWXKR3)O#(<>a)r^%+OKMIn9Q*``hK2f~a~)%6^$? z39lMnH-A96YRM*b4HO7+fcbII=ymyW#{$H))d19y6kq%tdl}~n^$#!Dlw{G{V`$< z(sK0Klwx_fY}OiNA&>ZVw1e!YlVjhSMpLF#sQydFI-o2;O9fHR*(UyH;b@BN-q6F$ zj!<1jEGI*5d(Qy?00000000000000000000005Og3xf7hbQa<500000NkvXXu0mjf Di}_Yk literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_1to2_warning_finalize_1/00003.png b/test/snapshots/nanosp/test_1to2_warning_finalize_1/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..0a22ed9c048e1c509e4db8bb538a09179382d08c GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oY9xMi-UOV|2+HP3fQ6_hr4)C!h3cBIwgUYi@Pc_i=RL3j}lbx08CSB=8DaK(Y*tb zSSyBpr8f#%7>3@&GbUmH006*nV<(Ij={|i+yB6(6M*X#uOEFU--rZ0f^L3jEn^|!> zns1flGuYyhdzXv&6Es3ES08$JK!g7x`*>onCgu&ixOswscDGZs rxUGg>FKO@BFS`N&0000008sJ;lcgi`7j@Bx00000NkvXXu0mjfZa}BF literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_1to2_warning_finalize_2/00001.png b/test/snapshots/nanosp/test_1to2_warning_finalize_2/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..42ed7069d748eb735e0c2ab4238ec4942ffbfee0 GIT binary patch literal 380 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 g2qAt<8 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_2to2_finalize_1/00003.png b/test/snapshots/nanosp/test_2to2_finalize_1/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff2c1b53d0183375101bf18ae0dc20891cf4a92 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{t1ba4!+nDh2VAm1Sco`yt| zdrQ9C2fcs9%(?P_MD#JP&;RF%%-K{{vRM(RhhcklrTzlf(6`ZoAEQoM$iHWOQ=M{W zGON&pjklGaE|XbPm*bQV6b!y9a`uOlOU{(l&4E&Lt}%UYc$IojO=ZkVlF~5@AhkM08`F3ou2$R=K z?%)@lGexx8cG->8U|VH%zlVorY}xl}9@mHGX3aid@`E`|FYcGL{NN(`X^U`5k%7oV fR#1o_fwrGaKc9YyNj)v*4-)ls^>bP0l+XkK$)2O@ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_2to2_finalize_1/00004.png b/test/snapshots/nanosp/test_2to2_finalize_1/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O00007f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_decred_sign_message/00000.png b/test/snapshots/nanosp/test_decred_sign_message/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1b271542d4bdb2b420bf296e4efb75129bcde20b GIT binary patch literal 415 zcmV;Q0bu@#P)5YKJ%(KU&1ONcAAJx@!`E?Y1^<~WN}zCyXs#X zo?o6k@9c|LZskJhD8km*o@uZbHa}-B?&(7HD5C%IYmwHRbJ)2) z`V`bZme<8JnX>F>hL3vOBL0b~>J+pM|9!ySI57nP0000WkROv_^0k3i)wKWs002ov JPDHLkV1lAe!YTj& literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_decred_sign_message/00001.png b/test/snapshots/nanosp/test_decred_sign_message/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..8e89ce6ac2cdb48d5b198770233b9ac2dd74efb8 GIT binary patch literal 671 zcmV;Q0$}}#P)cmxkRwzA=Bj;SUfAdp$K6lfYq!D%-yEc%@YbDd)>8)=-d5hhd zH&d!5`Hy7$Ubn$R*e;B6+nAp(!;&|^rOXYy8FsG$KVBW8+l#SkI`iLv+FaN4T#;g@ z7fG|J8(beXLjWS>ZrEADst^_Md$Gfh zbqB5#EA+*45>TU`QnKyIF2NEo8exJ)U&1Az=yDJ@`VuYyHN-XOp`$M%FY68*p+}*h z(U)*{K+%OeZuDadH{}Na0KgCvyIXC9*F*FlKf52EorlxTjav_K(~r;hp>DrwlZO}j zwr6dBbo<_x(x_Xm>iJ$Z;4j@|WmIA-?K&T$mb$Gs7Qg#_ZK(f>ary!=ky096`v93!glD3*naE2reFw84s5}EFhnMx8M+=#Y`}j=5V|8hB_ d00000AiqMIDtg(-y_Em}002ovPDHLkV1f$&;L!j8 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_decred_sign_message/00003.png b/test/snapshots/nanosp/test_decred_sign_message/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..9088cece139d94e6aa44cc37a3f242f8a4c18e2d GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-&ba4!+nDh2Vv{17Gk3-<{ z%X2sUSKT?i&fxKdh7SHo9N%lUh6r#TIkX9=2L>7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_get_pubkey/00000.png b/test/snapshots/nanox/test_1to2_get_pubkey/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ef59ec33cae7873dd8319576fd925025f9da36d9 GIT binary patch literal 701 zcmV;u0z&KXnwA0p00000z-Mxv=Xsv~j|};@ z<2&1cQeF9Pd^*HWwgD<)Jj7}^j^i3Xj)TbfN3uw+0OC+m4a7C#AW>3fL`Rdkd}Ke5 zr~u+DXYR)|v>w+Yx|94KP;O|dM?>j3J-7E{2B1E9yA@n}Iv4ijsUh>s{il@jmAJOO zCy0GgYo}U9KfehB00000fEUhJ46&{rW5oWnE8iY{yQYfTY-2p~;?hpbzo3K>@?KGak^BXkTk(?LKqE&|R zS(lxf_i*{z=ho)2tuwtbcl!u2Q1P4q>R(qjQ%C6 zhAttr6`fy~BgQQe*3K-GEYYSNqqNg#S2%tU(<0Avq$s})sUHPSMq~lvM5&*H}4o(j$uG^A&h zJ-Ngz8K{6&#lC;j*u&`7G==y#qs_^kPHHl j3<3ZE00000z~}J`zqCQ$s2e_`00000NkvXXu0mjf@^wc| literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_get_pubkey/00001.png b/test/snapshots/nanox/test_1to2_get_pubkey/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_hash_input_finalize/00000.png b/test/snapshots/nanox/test_1to2_hash_input_finalize/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..487ea10fcfeb2f3e6b79239459672251d49addd7 GIT binary patch literal 414 zcmV;P0b%}$P)vpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*a0XUzZionjl!99%>gfx6_pLqkn}X)*nAi*M-g;QqVG?!@K$ z>tArs2)Y{N#T%@BrN}zrM{n-abC3N}`MZVeneTXPk zo!LX$lPb;-AUs zazJ;lnSWz``D%yVHCsaePCHz%aOcMDk5`rXe-+u>yWk<$-CW_bS?5DtJwGa#eVNcW zb33zG#q*gzvm(tN-@CG(dB^VAXB+h2JxG`MH)$ucSziCQwb$Gu}~gecV$*KQ# zeD8K3y+ZkKV%o&dZU?HE`7mcg&iO9SIg2`Y$u2g}01;3z8$@W#LSf`p#|*S+t4p5e zh#4S)1&;kb3uVM>8GVxddq7&Sspf(d1%2<{vois&Coh+RdrjAsk#XwOIdlCEh3`);bB1GpXS%#2lB}ayv7XL1)sJ@o{<| z660Q`@BW^-QfkpcuM$pMXOw_ON>f_i(7yS0h7u62p297}A#J=nyQTx>*sRrmlKupQ zI~XYGI1EOlBWK{Soye#f>I^8bg5UNK&2k-b2ACt-AH{fpbQ7H(b7J|c&`6GJ9xftS zOZUE-n9_TP5x>dwm{bj(@KM6J4-*qG{XL!6;|bB9Leqm>f2{Mz=^7{^YdCrp`u7Au zW)7C3!|SP`rhFKlQxkAU>mU@GYCa$(p#&>rkD9P*`ZE-SCLIyfO-I~lt>CMzPTNrR z#D!JALLfz$>Q!rQYpNOY=0N-@?97^E_!9|*DvjMtQ=b+TeneG*)bRyQ(1_!J?nRU| zJ&{94+qK_@F4CxdRayKLD*H|stwJoaod^Ok?rz^LwoFuMnmT=;7abWLC?t8yzYSfH zgTZ03lw72vOg{}1?Nj`$Cm vx8T72h7dvsA%qY@2qAK;A6FlvHV~3(j}{OW?S(s1?pnB{C5rCfyJx7E$&#;rE;#glp#5O z=65YeM!z@r7hPKx`=&0}x&JC-&&sT`&k7Zl%ue4u>KuC~tSQ~0eD-e_mDBbL@!VSb zg`6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O00007f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_warning_finalize/00000.png b/test/snapshots/nanox/test_1to2_warning_finalize/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..d08297ed46739c96729072ae4af65cfdfe409c8a GIT binary patch literal 529 zcmV+s0`C2ZP)VJiL^(Q~-=mUqmg~>)&k#hN0kDkLFpoI= zx41Jv`8uNOcjBFbHjbe$;WI8`000000K=(oFrD{+T2V@Ae|Ymq{)mz}^qHD-mY;Nn zB2r34i!6UOkA$1bNZq-06IMe&8D~DPyGp$^m6#g#p`=nV=F~j4!C7N1)@rYZG7p{) z#+l74v&0Odr9WCqq<~5Qn9Y{6^V9}sjjb8qG5e+2KUY7#T9Yc6Z~b~6x51RJNB4uM zK{K`k3U@XMIRO1mtSj}~&{3mbvod3BKH#{`oOBc3VWX>= z+5xRAek*>b>6?;w#CPW+}E8Ua|@S0000000000zzlu?TmF3^ T7S#2+00000NkvXXu0mjf{Wk1G literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_warning_finalize/00001.png b/test/snapshots/nanox/test_1to2_warning_finalize/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..936cbee44304c692fdafc753aa00441a9272af53 GIT binary patch literal 554 zcmV+_0@eMAP)G%00013&X=k8<2d5jdmklX zd~?=>`eWz%LAefW3D~dz9pcJJmqjWGLhpS?bLb(PtFIp=SsAhbF6Z0A>5%MZ{0sLt zHK7I_^Q^74iloe#`b?D{+=6tfDVwzwon#AZJNpZeK7e`>UG1T^o6(LvE$Ad^mzZr4 zciR*g79c)i0Yy#pocUBHs=jqw@8|8y;-+M&5i@o3gg&wbeG<06gfFMsG!&D&wSEAA zN22WWTI1@~a&J?P-_S{~R(Gh?sl~gi8n(=@+=F%IXeCAWaDGsxcsR?oF;{i^1(?`| z9*s|9rM$J}Xn9a<`#N@;93|#6w(7SaJ^N>(SxI~_Lsan#T^eNPu1n3-TgNuT_CV(C z+9m8%=y!Ldxf5M5m z43bO@Oexd*uoE%YI9|^rV94S->P)NfbY7VUzCM>2GBlFY8xaofah`MwLvliR7{^IuOkEi004j;Nax1o zLaX;BK2JGwT-->(ntzGEC`4TpkzUwfF4Gnm82jxC@VdLe5y_XsrQpEz})ru&D0f-(ohXrF6j&Io=Rk z#oC#zh0hkzT9U!I|L+8|dS6(z2cM(5mcW1uw?vm+6Ad+Yw(_B0gy+$TJY`8!$=V4T zgA2e&2Y2L==5DT|l=lH30){^T005AaU)@e0{yUmS8Oe|D3)Oo83~|B|N4bUJ%!NFE z4$y~BFLFtKShN!^6=Fpdv2f->j_+CSB^IqT;|iK3;moycXMkD6oy^o?vcu1G&o4oO zK(umX{h1PYC)*i-{MDZ3Q%6Ru-)(e8M#-Se-4!|1j!jMc=4!j z_CJRO);kNf|C#^xTYZvZt?H%gi`lBKIP^;~T)*|9>>tm^$s6J??VLTmiitVa@RZl# z9D}7HW~IBg#_v|Osdspo)b@#I##$}$!vTL1erwOq|6RGGG~%xIOYz59T*k-q6J81a z$=e)pd!KrK?JqHvo`lxakeiYh%(DN_TKY9re^&30zAaAgrtV<9s?#_7_s4|tE$2+UT~i!DCi)dVeekXbfGQn;e2~0fAOicmauuP0002Mzj&=KKtD4J$KLye zCAmVf0^-oe6stk60z&lTa2HQXc&{!%rzFsFaaUz#@%^X$QG#j@z%sRFuGsvYZVyOe ztr+@^-Ym#54ZVqHEW`i+0D$S{E*LG+oje>5E!vID`fC@rVwOa_yP*usci2kU%!B_NjoM%I`cQE8xLXmr?Tj{%7E&qO)?n_k!~17dJ04(N+iTeNYvWx1c8xtAH@l);a;EJNPI@g;)=W jG2Q|I00000065_bLe?2BGhBsU00000NkvXXu0mjf6RxS% literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_warning_finalize_1/00001.png b/test/snapshots/nanox/test_1to2_warning_finalize_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..a6c5bdbf3c27d8adcb839d4830f2e9221390b6a3 GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=ltba4!+nDh2#bkSi29*4lK zm*;Nyuex!1ox$OZBd5!lf@W9mo0GsH=$N1c(p9r&PVu>$yT$qT?X^}=3UaQ`;d#{a zy}z8jt>~QQQlVv4f$LuL-YqZDz1)}Sb^qDXdbSzyi|Qhimg}F%-CFWfa97n{Kh2+R z@k%@nh1z1dN1C5ZW?!^q!G7t3;+E$b=FYnP#O~5L(eFN=B05BtO#ZZ1>u%_lSOc}I z_GQl)85n;2x^-pU&3i9v7wTo57uscg;^ac#=q)wr{|c+bcfW~0u{`YvT z7n$0f*Bs7g;O5WvTTWa??#Q-(Q{poJoD#lsyR|~7Eb)+S=f7)>oaGYRAFp<^%kMB^ z5cmHkzg_3-p$qFSRc*bnb=x!5b`g`#P5*YkTC(KCP2T>wjQKJj-pQ?N`4M)=u-@>M z-!|9Dc`i5H^$tl}hX0d3tRVb1*=nKMuXaPWc_*Cai8-e6Y*X3;3^QbKz-<4N{~`fL SSHG7B346NwxvX$hB`1VW9}+O+Q)>2Ex%?cOt!P3036|1_nptO`epsnPjJc=61k|C2CLfWc zD8|WS{r}fazXBX_ImxAm+p`PHe~KMYaANuUmi&-sH8bgF{~&LXDTh(%05wUf zZmAPR&5CrrCeu$ZHtjMsealo$nRPXE)^hPNuz>V>xC5U7R<I!T@(?#dOh3yFSl;sKFVwC^@%Bsu-mCEsVR9dU zA?B|_AWslv^ueXb@WwCYty2=yWXKR3)O#(<>a)r^%+OKMIn9Q*``hK2f~a~)%6^$? z39lMnH-A96YRM*b4HO7+fcbII=ymyW#{$H))d19y6kq%tdl}~n^$#!Dlw{G{V`$< z(sK0Klwx_fY}OiNA&>ZVw1e!YlVjhSMpLF#sQydFI-o2;O9fHR*(UyH;b@BN-q6F$ zj!<1jEGI*5d(Qy?00000000000000000000005Og3xf7hbQa<500000NkvXXu0mjf Di}_Yk literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_warning_finalize_1/00003.png b/test/snapshots/nanox/test_1to2_warning_finalize_1/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..0a22ed9c048e1c509e4db8bb538a09179382d08c GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oY9xMi-UOV|2+HP3fQ6_hr4)C!h3cBIwgUYi@Pc_i=RL3j}lbx08CSB=8DaK(Y*tb zSSyBpr8f#%7>3@&GbUmH006*nV<(Ij={|i+yB6(6M*X#uOEFU--rZ0f^L3jEn^|!> zns1flGuYyhdzXv&6Es3ES08$JK!g7x`*>onCgu&ixOswscDGZs rxUGg>FKO@BFS`N&0000008sJ;lcgi`7j@Bx00000NkvXXu0mjfZa}BF literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_warning_finalize_2/00001.png b/test/snapshots/nanox/test_1to2_warning_finalize_2/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..42ed7069d748eb735e0c2ab4238ec4942ffbfee0 GIT binary patch literal 380 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 g2qAt<8 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_2to2_finalize_1/00003.png b/test/snapshots/nanox/test_2to2_finalize_1/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff2c1b53d0183375101bf18ae0dc20891cf4a92 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{t1ba4!+nDh2VAm1Sco`yt| zdrQ9C2fcs9%(?P_MD#JP&;RF%%-K{{vRM(RhhcklrTzlf(6`ZoAEQoM$iHWOQ=M{W zGON&pjklGaE|XbPm*bQV6b!y9a`uOlOU{(l&4E&Lt}%UYc$IojO=ZkVlF~5@AhkM08`F3ou2$R=K z?%)@lGexx8cG->8U|VH%zlVorY}xl}9@mHGX3aid@`E`|FYcGL{NN(`X^U`5k%7oV fR#1o_fwrGaKc9YyNj)v*4-)ls^>bP0l+XkK$)2O@ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_2to2_finalize_1/00004.png b/test/snapshots/nanox/test_2to2_finalize_1/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O00007f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_decred_sign_message/00000.png b/test/snapshots/nanox/test_decred_sign_message/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1b271542d4bdb2b420bf296e4efb75129bcde20b GIT binary patch literal 415 zcmV;Q0bu@#P)5YKJ%(KU&1ONcAAJx@!`E?Y1^<~WN}zCyXs#X zo?o6k@9c|LZskJhD8km*o@uZbHa}-B?&(7HD5C%IYmwHRbJ)2) z`V`bZme<8JnX>F>hL3vOBL0b~>J+pM|9!ySI57nP0000WkROv_^0k3i)wKWs002ov JPDHLkV1lAe!YTj& literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_decred_sign_message/00001.png b/test/snapshots/nanox/test_decred_sign_message/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..8e89ce6ac2cdb48d5b198770233b9ac2dd74efb8 GIT binary patch literal 671 zcmV;Q0$}}#P)cmxkRwzA=Bj;SUfAdp$K6lfYq!D%-yEc%@YbDd)>8)=-d5hhd zH&d!5`Hy7$Ubn$R*e;B6+nAp(!;&|^rOXYy8FsG$KVBW8+l#SkI`iLv+FaN4T#;g@ z7fG|J8(beXLjWS>ZrEADst^_Md$Gfh zbqB5#EA+*45>TU`QnKyIF2NEo8exJ)U&1Az=yDJ@`VuYyHN-XOp`$M%FY68*p+}*h z(U)*{K+%OeZuDadH{}Na0KgCvyIXC9*F*FlKf52EorlxTjav_K(~r;hp>DrwlZO}j zwr6dBbo<_x(x_Xm>iJ$Z;4j@|WmIA-?K&T$mb$Gs7Qg#_ZK(f>ary!=ky096`v93!glD3*naE2reFw84s5}EFhnMx8M+=#Y`}j=5V|8hB_ d00000AiqMIDtg(-y_Em}002ovPDHLkV1f$&;L!j8 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_decred_sign_message/00003.png b/test/snapshots/nanox/test_decred_sign_message/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..9088cece139d94e6aa44cc37a3f242f8a4c18e2d GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-&ba4!+nDh2Vv{17Gk3-<{ z%X2sUSKT?i&fxKdh7SHo9N%lUh6r#TIkX9=2L>7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_get_pubkey/00000.png b/test/snapshots/stax/test_1to2_get_pubkey/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..32a20c9f042cb2b57600928334d50b8a21421233 GIT binary patch literal 12646 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_get_pubkey/00001.png b/test/snapshots/stax/test_1to2_get_pubkey/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..eb3d03546ea699eba540460bdf5773c53568a24e GIT binary patch literal 4944 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 A@c;k- literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_get_pubkey/00002.png b/test/snapshots/stax/test_1to2_get_pubkey/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb33e0f2a387d452442e4ae97f4485208d9ce8d GIT binary patch literal 9215 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 TV-DWr%Q!o^ovl9;^viz$-cC%N literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00001.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..f655aa02919b5df6f6794fe1f8988f85585b3359 GIT binary patch literal 15536 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 AuK)l5 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00002.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..bafc92c05f4621bd9c8782378a40210860e3f8ea GIT binary patch literal 8545 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 H&@6SYv%)Dpx*fk`X6sWp?+ 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00004.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb33e0f2a387d452442e4ae97f4485208d9ce8d GIT binary patch literal 9215 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00001.png b/test/snapshots/stax/test_1to2_warning_finalize/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..bec40a0e7faac9d06918977b4e28004d86a05b79 GIT binary patch literal 8207 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00003.png b/test/snapshots/stax/test_1to2_warning_finalize/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..c06c4a93f280793661ba2300f13418cb73063b19 GIT binary patch literal 8484 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00004.png b/test/snapshots/stax/test_1to2_warning_finalize/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..6ec6d8c7989520d1b6c3c1836ea24f29b2baca83 GIT binary patch literal 8179 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 OVqs!!Tyf3w(Z2x)D?{x7 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00005.png b/test/snapshots/stax/test_1to2_warning_finalize/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..2bdbf32eeccd978e8e6dd98a788b0ce213726a96 GIT binary patch literal 13310 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 yShKV z(Qor(?%OSIto`}+P4cWmEoaF^0(ws*a%_I;Q$sIM7ax6m@IK`CT*oIse5mu9p$k?* z)g@|3svArbnX_&I!p3Z&B=`Mx9M7M>wWPoJcdT^(er4R1p-#6u-HkYP S9Qa=kkBOnh&59dN&;J){f7(X? literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00006.png b/test/snapshots/stax/test_1to2_warning_finalize/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..c06c4a93f280793661ba2300f13418cb73063b19 GIT binary patch literal 8484 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00007.png b/test/snapshots/stax/test_1to2_warning_finalize/00007.png new file mode 100644 index 0000000000000000000000000000000000000000..0150cabca9f0744cc4faff4087c067b93cf7db82 GIT binary patch literal 8078 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 ce_G!HVKwAnkQ);GpIywv2!5^ns>`GQ0tm=P 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 TV-DWr%Q!o^ovl9;^viz$-cC%N literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00001.png b/test/snapshots/stax/test_2to2_finalize_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..44ce6e007eff1c3858827a8373b313f02200ef53 GIT binary patch literal 15571 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 G_P+rJ;?)TN literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00002.png b/test/snapshots/stax/test_2to2_finalize_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..bafc92c05f4621bd9c8782378a40210860e3f8ea GIT binary patch literal 8545 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 H&@6SYv%)Dpx*fk`X6sWp?+ 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00004.png b/test/snapshots/stax/test_2to2_finalize_1/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb33e0f2a387d452442e4ae97f4485208d9ce8d GIT binary patch literal 9215 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_decred_sign_message/00001.png b/test/snapshots/stax/test_decred_sign_message/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..ca53da99978f0a4e65ef8587781e0effa2a564f6 GIT binary patch literal 12743 zcmeI3c{r5+zyGCDN@=rYt8A6A4%wILL&^3j5yFry%Mimb81s>&M6zTbS}cWZW8a39 z!HiKx#x#u~%fuLiVbEB9ci(gUuHX6hoa_3XbN)ED|J?U=-|y}9e!pIi=X0L^ZFB9& zq0@)>`1p=kT>tA9AK#uAe0=<`4)O#4(YI}{;N#PHZt>UU+mQt<8tY|wD-{$WSP ztDyd`KX*aLhgq)_k`?X?-g=n%O5wWTxLO^tA@sz-$;;>fHk^O@e8i|5{TOZ>Ygz7h_2^g!nb|F6>SbGkkM z!}{@GG?qI$sN-d%_fRSbpY-OSEv1n)7j`4PxV(Imxhf>$v0hd72qMR$^W zCSR2LIb{vq-LKxQ8RxyDA@0cA-hsE}Uci9zvGXRW?+K>cBjK*(H5NSD&AkD7m#iI^ z0J-09`LSp6SYcPO2%i3pj1_D zr|GCEOI?qjW}kvBy=KI#>BnA?_>qq0g$!#_flV2)^JQyQhP(wy%OagF=$^zZ{->3=e=vF%&K9 zo)V++`?X*YDJQ>FPwFVq6#+x1%Uj$$727iw)bw=y8OubmhV8ujp&{ovj`3arJ)WPQTr=x5I59r)beYKUkbq^P8le3EE=|}U)H7Rt4 zdex#)ulLHZ>!u|f(&fFKWR4zaW76t9`ZW{%Vy#IV(5@JH7TB5u!V}h>ZAJjYqnuJ; zm4hi99d=44Doi65T_$^jZ5*AlklvS+tVxaDw`W$-KlcRJKX4Z@3(=J#JpD)SXAg~4 zdUJngEz6;a%Cgc)ntP_f8pQ^S=;hK$AQnZ<)Qc(IptlE6h$~u?|4L2&>(0?70~IO9 ze(aRw(Zn7fOxpCJn3N`Hz~h6f*6zE(K=)1hv@UT{*P>WLAn}6AssPf*8K2xw6<{}d zW(|g1$~omTG7CBvdpEgHe_!nDnY|U|`yKP_|Ze_O3 `#=AQ7C!8#U16g4>6Wmj1ErZE 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 OJ_|FOzpAddKm0%Qp?8M> literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_decred_sign_message/00002.png b/test/snapshots/stax/test_decred_sign_message/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..81135073c955daf5d866915804ecd301ce2aaa1f GIT binary patch literal 8557 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_decred_sign_message/00003.png b/test/snapshots/stax/test_decred_sign_message/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..30e6112a09738229bdaa77ddf1ce9c929d6a9454 GIT binary patch literal 4293 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_decred_sign_message/00004.png b/test/snapshots/stax/test_decred_sign_message/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb33e0f2a387d452442e4ae97f4485208d9ce8d GIT binary patch literal 9215 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 e04800001e058000002c8000002a800000000000000000000002000000000000000001 HID <= 3144022041b371311dc2f2dc72b83e8249d3fc0f53f6bfc9ccdb214eeea7b35914ba187602200de4313f2dca0aa2ca857afb65e06d693128e6e4b9b127eff018ddcfe98c462e019000 -''' \ No newline at end of file +''' diff --git a/test/test_sign_message.py b/test/test_sign_message.py index 3a6320a..f392bee 100755 --- a/test/test_sign_message.py +++ b/test/test_sign_message.py @@ -15,40 +15,51 @@ #* See the License for the specific language governing permissions and #* limitations under the License. #******************************************************************************** -from ragger.backend import RaisePolicy -from ragger.navigator import NavInsID, NavIns -from binascii import hexlify import struct +from pathlib import Path +from inspect import currentframe +from binascii import hexlify +from ragger.backend import RaisePolicy +from ragger.navigator import NavInsID + ################# SIGN MESSAGE ######################### -def test_decred_sign_message(client, firmware, navigator): - client.raise_policy = RaisePolicy.RAISE_NOTHING +def test_decred_sign_message(backend, firmware, navigator): + backend.raise_policy = RaisePolicy.RAISE_NOTHING - magic = "\x18Bitcoin Signed Message:\n" + # magic = "\x18 Signed Message:\n" message = "Message to be signed" - data = magic + chr(len(message)) + message - hex_str_data = hexlify(bytes(data,'ascii' )) - hex_str_sign_msg = b'058000002c8000002A800000000000000100000001' + hexlify(struct.pack('>h', int(len(hex_str_data.decode('ascii'))/2))) + hex_str_data + data = chr(len(message)) + message + hex_str_data = hexlify(bytes(data, 'ascii')) + hex_str_sign_msg = b'058000002c8000002A800000000000000100000001' + hexlify( + struct.pack('>h', int( + len(hex_str_data.decode('ascii')) / 2))) + hex_str_data str_sign_msg = hex_str_sign_msg.decode('ascii') - packet = "e04e0001" + hexlify(bytes([int(len(str_sign_msg)/2)])).decode("utf-8") + str_sign_msg - result = client.exchange_raw(data=bytearray.fromhex(packet)) + packet = "e04e0001" + hexlify(bytes([int(len(str_sign_msg) / 2) + ])).decode("utf-8") + str_sign_msg + backend.exchange_raw(data=bytearray.fromhex(packet)) packet = "e04e80000100" - with client.exchange_async_raw(data=bytearray.fromhex(packet)) as r: - if firmware.device == "fat": - navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) - navigator.navigate([NavIns(id=NavInsID.TAPPABLE_CENTER_TAP)]) - navigator.navigate([NavIns(id=NavInsID.USE_CASE_REVIEW_CONFIRM)]) - if firmware.device in ["nanox","nanosp"]: - navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) - navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) - navigator.navigate([NavIns(id=NavInsID.BOTH_CLICK)]) - if firmware.device == "nanos": - navigator.navigate([NavIns(id=NavInsID.RIGHT_CLICK)]) - - # expected = "9e18e3a7e7508bdd151104b4879b350565aac97f031ee6eea5b7bf84029a929d00000000ac211e0000000000" - # # expected = "7dfed275d5fb94c2b7fd0a0e92f0b62e8324829c40dba2b09231b7763ab43c5700000000ac211e0000000000" - # if expected not in hexlify(result.data).decode("utf-8"): - # print("Error:\nExpected:%s\nGot: %s\n" % (expected,hexlify(result.data[4:-8]).decode("utf-8"))) - # exit() + path = Path(currentframe().f_code.co_name) + with backend.exchange_async_raw(data=bytearray.fromhex(packet)) as r: + if firmware.device == "stax": + navigator.navigate_until_text_and_compare( + NavInsID.TAPPABLE_CENTER_TAP, [ + NavInsID.USE_CASE_REVIEW_CONFIRM, + NavInsID.WAIT_FOR_HOME_SCREEN + ], "Hold", + Path(__file__).parent.resolve(), path) + else: + navigator.navigate_until_text_and_compare( + NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Accept", + Path(__file__).parent.resolve(), path) + + result = backend.last_async_response + + expected = "3045022100e841839bef7147f0bb79e7e301a0bfdb2ff8b1c4a195d9a18c4f167c70dd63e6022061898f34c11561ccd1ad74d627195aa5f08d7fff8f78eb9de605e433d8532783" + assert result.status == 0x9000 + if expected not in hexlify(result.data).decode("utf-8"): + print("Error:\nExpected:%s\nGot:%s\n" % + (expected, hexlify(result.data).decode("utf-8"))) + exit() From 701befd1a5bd4e48f8c447069b674ef8a9242760 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 27 Apr 2023 11:02:27 +0200 Subject: [PATCH 32/41] Remove broken old UI for Nano S and use ux_flow lib (like LNSP,LNX) --- Makefile | 3 +- src/main.c | 4 - src/ui/ui_main_menu_bagl.c | 49 ----- src/ui/ui_pubkey_bagl.c | 193 ------------------- src/ui/ui_transaction_bagl.c | 355 +---------------------------------- 5 files changed, 9 insertions(+), 595 deletions(-) diff --git a/Makefile b/Makefile index b8e9b3c..c476ed9 100755 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ ifeq ($(TARGET_NAME),TARGET_STAX) DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += NBGL_QRCODE NBGL_USE_CASE NBGL_PAGE else - DEFINES += HAVE_BAGL + DEFINES += HAVE_BAGL HAVE_UX_FLOW endif # BLE @@ -117,7 +117,6 @@ DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -DEFINES += HAVE_UX_FLOW endif # Enabling debug PRINTF diff --git a/src/main.c b/src/main.c index d6cf2cb..0aeba0a 100644 --- a/src/main.c +++ b/src/main.c @@ -58,13 +58,9 @@ unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e); #endif void ui_idle(void); -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) #include "ux.h" ux_state_t G_ux; bolos_ux_params_t G_ux_params; -#else -ux_state_t ux; -#endif // TARGET_NANOX || TARGET_NANOS2 #ifndef TARGET_STAX // override point, but nothing more to do diff --git a/src/ui/ui_main_menu_bagl.c b/src/ui/ui_main_menu_bagl.c index fb9d289..b427a79 100644 --- a/src/ui/ui_main_menu_bagl.c +++ b/src/ui/ui_main_menu_bagl.c @@ -26,49 +26,6 @@ // #include "btchip_bagl_extensions.h" -#if defined(TARGET_NANOS) - -const ux_menu_entry_t menu_main[]; -const ux_menu_entry_t menu_settings[]; - -// change the setting -void menu_settings_pubKeyRequestRestriction_change(unsigned int enabled) { - nvm_write((void*) &N_btchip.pubKeyRequestRestriction, &enabled, 1); - // go back to the menu entry - UX_MENU_DISPLAY(0, menu_main, NULL); -} -const ux_menu_entry_t menu_settings_pubKeyRequestRestriction[] = { - {NULL, menu_settings_pubKeyRequestRestriction_change, 1, NULL, "Manual approval", NULL, 0, 0}, - {NULL, menu_settings_pubKeyRequestRestriction_change, 0, NULL, "Auto approval", NULL, 0, 0}, - UX_MENU_END}; -const ux_menu_entry_t menu_settings[] = { - {menu_settings_pubKeyRequestRestriction, NULL, 0, NULL, "Public keys", "export approval", 0, 0}, - {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, - UX_MENU_END}; - -const ux_menu_entry_t menu_about[] = { - {NULL, NULL, 0, NULL, "Version", APPVERSION, 0, 0}, - {menu_main, NULL, 1, &C_nanos_icon_back, "Back", NULL, 61, 40}, - UX_MENU_END}; - -static void menu_exit_callback(unsigned int userid) { - UNUSED(userid); - os_sched_exit(0); -} - -const ux_menu_entry_t menu_main[] = { - //{NULL, NULL, 0, &NAME3(C_nanos_badge_, COINID, ), "Use wallet to", "view - // accounts", 33, 12}, - {NULL, NULL, 0, NULL, "Use wallet to", "view accounts", 0, 0}, - {menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0}, - {menu_about, NULL, 0, NULL, "About", NULL, 0, 0}, - {NULL, menu_exit_callback, 0, &C_nanos_icon_dashboard, "Quit app", NULL, 50, 29}, - UX_MENU_END}; - -#endif // #if defined(TARGET_NANOS) - -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) - const char* settings_submenu_getter(unsigned int idx); void settings_submenu_selector(unsigned int idx); @@ -163,20 +120,14 @@ UX_FLOW(ux_idle_flow, &ux_idle_flow_2_step, &ux_idle_flow_3_step, &ux_idle_flow_4_step); -#endif void ui_idle(void) { ux_step_count = 0; ux_loop_over_curr_element = 0; - -#if defined(TARGET_NANOS) - UX_MENU_DISPLAY(0, menu_main, NULL); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) // reserve a display stack slot if none yet if (G_ux.stack_count == 0) { ux_stack_push(); } ux_flow_init(0, ux_idle_flow, NULL); -#endif // #if TARGET_ID } #endif // HAVE_BAGL diff --git a/src/ui/ui_pubkey_bagl.c b/src/ui/ui_pubkey_bagl.c index 24bfec7..b1e0041 100644 --- a/src/ui/ui_pubkey_bagl.c +++ b/src/ui/ui_pubkey_bagl.c @@ -24,175 +24,6 @@ #include "string.h" #include "btchip_internal.h" -#if defined(TARGET_NANOS) - -unsigned int ui_display_address_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); -unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); -unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -const bagl_element_t ui_display_address_nanos[] = { - - UI_NANOS_BACKGROUND(), - - /* Displayed when derivation path is unusual */ - - UI_NANOS_TEXT(1, 0, 22, 128, "Warning !", BAGL_FONT_OPEN_SANS_LIGHT_16px), - - UI_NANOS_TEXT(2, 0, 12, 128, "The derivation", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(2, 0, 26, 128, "path is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Derivation path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, - 15, - 26, - 98, - vars.tmp_warning.derivation_path, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - /* Always displayed */ - - UI_NANOS_ICON_LEFT(5, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(5, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(5, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(5, 0, 26, 128, "address", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(6, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - // Hax, avoid wasting space - UI_NANOS_SCROLLING_TEXT(0x86, - 15, - 26, - 98, - G_io_apdu_buffer + 199, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - -const bagl_element_t ui_request_pubkey_approval_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Export", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, "public key?", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - -const bagl_element_t ui_display_token_nanos[] = { - - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm token", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - // Hax, avoid wasting space - UI_NANOS_TEXT(1, 0, 26, 128, G_io_apdu_buffer + 200, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - -unsigned int ui_display_address_nanos_prepro(const bagl_element_t* element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); - if (display) { - switch (element->component.userid) { - case 0x83: - ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - case 5: - UX_CALLBACK_SET_INTERVAL(2000); - ux_loop_over_curr_element = - 0; // allow next timer to increment ux_step when triggered - break; - case 0x86: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - // ugly ux tricks, loops around last 2 screens - ux_step -= 1; // loops back to previous element on next redraw - ux_loop_over_curr_element = 1; // when the timer will trigger, ux_step won't be - // incremented, only redraw - break; - } - } - return display; - } - return 1; -} - -unsigned int ui_display_address_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - if (ux_step == 3) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - break; - } - } else if (ux_step >= 4) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } else { - if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { - // if we were looping over a single element, disable this loop and diffuse the redisplay - // timeout (used by scrolling text) - if (ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - } - } - return 0; -} - -unsigned int ui_request_pubkey_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - return 0; -} - -unsigned int ui_display_token_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_token_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_token_ok(NULL); - break; - } - return 0; -} - -#endif - -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) - UX_STEP_NOCB(ux_display_public_flow_1_step, pnn, { @@ -299,8 +130,6 @@ UX_STEP_VALID(ux_display_token_flow_2_step, UX_FLOW(ux_display_token_flow, &ux_display_token_flow_1_step, &ux_display_token_flow_2_step); -#endif - void ui_display_public_key(unsigned char* derivation_path) { // append a white space at the end of the address to avoid glitch on nano S strcat((char*) G_io_apdu_buffer + 200, " "); @@ -310,39 +139,17 @@ void ui_display_public_key(unsigned char* derivation_path) { MAX_DERIV_PATH_ASCII_LENGTH); uint8_t is_derivation_path_unusual = bip44_derivation_guard(derivation_path, false); -#if defined(TARGET_NANOS) - // prepend a white space to the address - G_io_apdu_buffer[199] = ' '; - ux_step = is_derivation_path_unusual ? 0 : 4; - ux_step_count = 6; - UX_DISPLAY(ui_display_address_nanos, ui_display_address_nanos_prepro); - -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init( 0, is_derivation_path_unusual ? ux_display_public_with_warning_flow : ux_display_public_flow, NULL); -#endif // TARGET_NANOX } void ui_display_request_pubkey_approval(void) { -#if defined(TARGET_NANOS) - // append and prepend a white space to the address - ux_step = 0; - ux_step_count = 1; - UX_DISPLAY(ui_request_pubkey_approval_nanos, NULL); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); -#endif // #if TARGET_ID } void ui_display_token(void) { -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 1; - UX_DISPLAY(ui_display_token_nanos, NULL); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_display_token_flow, NULL); -#endif // #if TARGET_ID } #endif // HAVE_BAGL diff --git a/src/ui/ui_transaction_bagl.c b/src/ui/ui_transaction_bagl.c index 448655b..52e8874 100644 --- a/src/ui/ui_transaction_bagl.c +++ b/src/ui/ui_transaction_bagl.c @@ -23,304 +23,6 @@ #include "string.h" #include "btchip_internal.h" -#if defined(TARGET_NANOS) - -const bagl_element_t ui_request_change_path_approval_nanos[] = { - UI_NANOS_BACKGROUND(), - - UI_NANOS_TEXT(1, 0, 22, 128, "Warning !", BAGL_FONT_OPEN_SANS_LIGHT_16px), - - UI_NANOS_TEXT(2, 0, 12, 128, "The change path", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(2, 0, 26, 128, "is unusual", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Change path", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(0x83, - 15, - 26, - 98, - vars.tmp_warning.derivation_path, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_ICON_LEFT(4, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(4, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(4, 0, 12, 128, "Reject if you're", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(4, 0, 26, 128, "not sure", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - -unsigned int ui_request_change_path_approval_nanos_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == (0x7F & element->component.userid) - 1); - if (display) { - if (element->component.userid & 0x80) { - ux_loop_over_curr_element = 1; - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - } - } - return display; - } - return 1; -} - -unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -const bagl_element_t ui_verify_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, "transaction", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Amount", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, - 23, - 26, - 82, - vars.tmp.fullAddress, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(4, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(4, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) - -}; -unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); - -const bagl_element_t ui_verify_output_nanos[] = { - - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Amount", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.fullAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(3, 0, 12, 128, "Address", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(3, - 23, - 26, - 82, - vars.tmp.fullAddress, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; - -unsigned int ui_verify_output_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -const bagl_element_t ui_finalize_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Confirm", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, "transaction", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Fees", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_SCROLLING_TEXT(2, 23, 26, 82, vars.tmp.feesAmount, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px) - - /* TODO - {{BAGL_LABELINE , 0x02, 0, 12, 128, 12, 0, 0, 0 , - COLOR_WHITE, COLOR_BLACK, - BAGL_FONT_OPEN_SANS_REGULAR_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, "Amount", - 0, 0, 0, NULL, NULL, NULL }, - {{BAGL_LABELINE , 0x02, 23, 26, 82, 12, 0x80|10, - 0, 0 , COLOR_WHITE, COLOR_BLACK, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 26 }, - vars.tmp.fullAmount, 0, 0, 0, NULL, NULL, NULL }, - */ -}; -unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter); - -// display or not according to step, and adjust delay -unsigned int ui_verify_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - case 4: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -unsigned int ui_verify_output_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - case 3: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -unsigned int ui_finalize_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -const bagl_element_t ui_verify_message_signature_nanos[] = { - UI_NANOS_BACKGROUND(), - UI_NANOS_ICON_LEFT(0, BAGL_GLYPH_ICON_CROSS), - UI_NANOS_ICON_RIGHT(0, BAGL_GLYPH_ICON_CHECK), - UI_NANOS_TEXT(1, 0, 12, 128, "Sign the", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - UI_NANOS_TEXT(1, 0, 26, 128, "message", BAGL_FONT_OPEN_SANS_EXTRABOLD_11px), - - UI_NANOS_TEXT(2, 0, 12, 128, "Message hash", BAGL_FONT_OPEN_SANS_REGULAR_11px), - UI_NANOS_SCROLLING_TEXT(2, - 23, - 26, - 82, - vars.tmp.fullAddress, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px)}; -unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter); - -unsigned int ui_verify_message_prepro(const bagl_element_t *element) { - if (element->component.userid > 0) { - unsigned int display = (ux_step == element->component.userid - 1); - if (display) { - switch (element->component.userid) { - case 1: - UX_CALLBACK_SET_INTERVAL(2000); - break; - case 2: - UX_CALLBACK_SET_INTERVAL( - MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7))); - break; - } - } - return display; - } - return 1; -} - -unsigned int ui_verify_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; - } - return 0; -} - -unsigned int ui_verify_output_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; - } - return 0; -} - -unsigned int ui_finalize_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_verify_ok(NULL); - break; - } - return 0; -} - -unsigned int ui_verify_message_signature_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_message_signature_verify_cancel(NULL); - break; - - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_message_signature_verify_ok(NULL); - break; - } - return 0; -} - -unsigned int ui_request_change_path_approval_nanos_button(unsigned int button_mask, - unsigned int button_mask_counter) { - UNUSED(button_mask_counter); - if (ux_step == 3) { - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - io_seproxyhal_touch_display_cancel(NULL); - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - io_seproxyhal_touch_display_ok(NULL); - break; - } - } else { - if (button_mask == (BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT)) { - // if we were looping over a single element, disable this loop and diffuse the redisplay - // timeout (used by scrolling text) - if (ux_loop_over_curr_element) { - ux_loop_over_curr_element = 0; - ux.callback_interval_ms = 0; - } - // prepare next screen - ux_step = (ux_step + 1) % ux_step_count; - // redisplay screen - UX_REDISPLAY(); - } - } - return 0; -} - -#endif // #if defined(TARGET_NANOS) - -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) - ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_sign_flow_1_step, pnn, @@ -340,8 +42,8 @@ UX_STEP_VALID(ux_sign_flow_3_step, io_seproxyhal_touch_message_signature_verify_ok(NULL), { &C_icon_validate_14, - "Sign", - "message", + "Accept", + "and sign", }); UX_STEP_VALID(ux_sign_flow_4_step, pbb, @@ -408,7 +110,7 @@ UX_FLOW(ux_confirm_full_flow, ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, {&C_icon_eye, "Review", "transaction"}); +UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, {&C_icon_eye, "Confirm output", vars.tmp.feesAmount}); UX_STEP_NOCB(ux_confirm_single_flow_2_step, bnnn_paging, { @@ -421,20 +123,14 @@ UX_STEP_NOCB(ux_confirm_single_flow_3_step, .title = "Address", .text = vars.tmp.fullAddress, }); -UX_STEP_NOCB(ux_confirm_single_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_VALID(ux_confirm_single_flow_5_step, +UX_STEP_VALID(ux_confirm_single_flow_4_step, pb, io_seproxyhal_touch_verify_ok(NULL), { &C_icon_validate_14, "Accept", }); -UX_STEP_VALID(ux_confirm_single_flow_6_step, +UX_STEP_VALID(ux_confirm_single_flow_5_step, pb, io_seproxyhal_touch_verify_cancel(NULL), { @@ -447,8 +143,7 @@ UX_FLOW(ux_confirm_single_flow, &ux_confirm_single_flow_2_step, &ux_confirm_single_flow_3_step, &ux_confirm_single_flow_4_step, - &ux_confirm_single_flow_5_step, - &ux_confirm_single_flow_6_step); + &ux_confirm_single_flow_5_step); ////////////////////////////////////////////////////////////////////// @@ -513,20 +208,11 @@ UX_FLOW(ux_request_change_path_approval_flow, &ux_request_change_path_approval_flow_3_step, &ux_request_change_path_approval_flow_4_step); -#endif // TARGET_NANOX || TARGET_NANOS2 - unsigned int ui_tx_confirm_full_output() { if (!prepare_full_output(0)) { return 0; } - -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 4; - UX_DISPLAY(ui_verify_nanos, ui_verify_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_confirm_full_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } @@ -538,14 +224,10 @@ unsigned int ui_tx_confirm_single_output() { snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), - "output #%d", + "#%d", btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1); -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 3; - UX_DISPLAY(ui_verify_output_nanos, ui_verify_output_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined (TARGET_NANOS) ux_flow_init(0, ux_confirm_single_flow, NULL); #endif // TARGET_NANOX || TARGET_NANOS2 return 1; @@ -555,14 +237,7 @@ unsigned int ui_tx_finalize() { if (!prepare_fees()) { return 0; } - -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 2; - UX_DISPLAY(ui_finalize_nanos, ui_finalize_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_finalize_flow, NULL); -#endif // TARGET_NANOX return 1; } @@ -570,26 +245,12 @@ void ui_tx_confirm_message_signature() { if (!prepare_message_signature()) { return; } - -#if defined(TARGET_NANOS) - ux_step = 0; - ux_step_count = 2; - UX_DISPLAY(ui_verify_message_signature_nanos, ui_verify_message_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_sign_flow, NULL); -#endif // TARGET_NANOX } void ui_tx_request_change_path_approval(unsigned char *change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); -#if defined(TARGET_NANOS) - // append and prepend a white space to the address - ux_step = 0; - ux_step_count = 4; - UX_DISPLAY(ui_request_change_path_approval_nanos, ui_request_change_path_approval_nanos_prepro); -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) ux_flow_init(0, ux_request_change_path_approval_flow, NULL); -#endif // #if TARGET_ID } #endif \ No newline at end of file From a28c8ecb08c6d29b15243cd40991dc4aea708f4b Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 27 Apr 2023 11:03:21 +0200 Subject: [PATCH 33/41] Add CI lint check for tests files + update .gitignore + update BLE_power device name. --- .github/workflows/build_and_functional_tests.yml | 2 +- .github/workflows/coding_style_checks.yml | 15 +++++++++++++-- .github/workflows/guidelines_enforcer.yml | 2 +- .gitignore | 7 ++++--- src/main.c | 2 +- src/ui/ui_transaction_bagl.c | 6 +++--- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml index 30509b3..d6de10a 100644 --- a/.github/workflows/build_and_functional_tests.yml +++ b/.github/workflows/build_and_functional_tests.yml @@ -1,4 +1,4 @@ -name: Build and run functional tests using ragger through reusable workflow +name: Ragger functional tests on: workflow_dispatch: diff --git a/.github/workflows/coding_style_checks.yml b/.github/workflows/coding_style_checks.yml index 3201b11..a9f34af 100644 --- a/.github/workflows/coding_style_checks.yml +++ b/.github/workflows/coding_style_checks.yml @@ -1,4 +1,4 @@ -name: Run coding style check through reusable workflow +name: Coding style checks on: workflow_dispatch: @@ -11,9 +11,20 @@ on: jobs: check_linting: - name: Check linting + name: Check sources linting uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_lint.yml@v1 with: source: './src' extensions: 'h,c' version: 11 + + tests_lint_check: + name: Check tests linting + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v3 + - run: pip install yapf toml + - name: Yapf source formatting + run: | + yapf test/ --recursive -d diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml index 7f2ab0d..a72f8e0 100644 --- a/.github/workflows/guidelines_enforcer.yml +++ b/.github/workflows/guidelines_enforcer.yml @@ -1,4 +1,4 @@ -name: Ensure compliance with Ledger guidelines +name: Guideline enforcer on: workflow_dispatch: diff --git a/.gitignore b/.gitignore index d9280d1..c9e6667 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ bin debug dep obj -src/glyphs.c -src/glyphs.h - +build +test/__pycache__ +test/snapshots-tmp +scan-build \ No newline at end of file diff --git a/src/main.c b/src/main.c index 0aeba0a..fb26e1d 100644 --- a/src/main.c +++ b/src/main.c @@ -257,7 +257,7 @@ __attribute__((section(".boot"))) int main(int arg0) { #ifdef HAVE_BLE BLE_power(0, NULL); - BLE_power(1, "Nano X"); + BLE_power(1, NULL); #endif // HAVE_BLE app_main(); diff --git a/src/ui/ui_transaction_bagl.c b/src/ui/ui_transaction_bagl.c index 52e8874..5e1d968 100644 --- a/src/ui/ui_transaction_bagl.c +++ b/src/ui/ui_transaction_bagl.c @@ -110,7 +110,9 @@ UX_FLOW(ux_confirm_full_flow, ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, {&C_icon_eye, "Confirm output", vars.tmp.feesAmount}); +UX_STEP_NOCB(ux_confirm_single_flow_1_step, + pnn, + {&C_icon_eye, "Confirm output", vars.tmp.feesAmount}); UX_STEP_NOCB(ux_confirm_single_flow_2_step, bnnn_paging, { @@ -227,9 +229,7 @@ unsigned int ui_tx_confirm_single_output() { "#%d", btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + 1); -#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined (TARGET_NANOS) ux_flow_init(0, ux_confirm_single_flow, NULL); -#endif // TARGET_NANOX || TARGET_NANOS2 return 1; } From 8a6928f4c8f4f63f36bc3670c506b77f4b522018 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 27 Apr 2023 12:11:54 +0200 Subject: [PATCH 34/41] Remove Blue icons. --- blue_app_decred.gif | Bin 1744 -> 0 bytes blue_app_decred_testnet.gif | Bin 817 -> 0 bytes decred.png | Bin 3039 -> 0 bytes decred_testnet.png | Bin 17743 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 blue_app_decred.gif delete mode 100644 blue_app_decred_testnet.gif delete mode 100644 decred.png delete mode 100644 decred_testnet.png diff --git a/blue_app_decred.gif b/blue_app_decred.gif deleted file mode 100644 index 9839ef9e0e43b4d86b3677b3508a480a94feef64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1744 zcmZ?wbhEHbG-5Df*v!Dtx&8nDe?J)V{>#+=Uw!)j<;VYRdjB7~`9E{Xe}=68Pu~51 z`{h4F+5ewEfBygfpP}%-;(zW4-v9-d#F9iHZDU_ikeHmETB4AYnx2_wtMq>NekFy> z6kDZmQ(pt$0_W6>OpmIf)Zi+=kmRcDWXlvKdpiZ23ag6Tg51=SM1_jnoV;SI3R|Vb zl>DSrDJTJZ)mJ*Xl7+%U}a>a00l}w+lo@stb$zJpmqUywn`Z#B?VUc`sL;2dgaD?`97yetOgf{R2HP_2c;J0 zmlh?b0+lO+tSYc_E=o--$uA1Y&(DE{Vn9ZINq%ugeu09sGbq$76*PPklQZ)`f|_7m zzP?tTdBr7(dC94sF1AWQbM!JZQ>=_kOw5d&EsR|(ogEDgT`e3Enm@@7}(7{p#h5=g*!#dHm?%gZuaH-no72=8fyuu3ou(>Eea+=gyuved^?i(;JWy=vu(<;#{XS-fcBg8B32&Y3-H=8Wmn zrcRkWY2t+bzTTehuFj73w$_&BrpAW)y4srRs>+J;veJ^`qQZjwyxg4Ztjvt`wA7U3 zq{M{yxY(HJsK|)$u+Wg;puhlsKVKhjFHaA5H&+*DCr1Z+J6juTD@zM=GgA{|BSQmy zJzX7bElmw|HB}X5B}D~!IawKLDM<-&F;Nj=AwdCtK3*PfE=~@1HdYp9CPoGZ#h)w; zAfN*xK&1==%l{20EuAx36^!ToPxxWL%p}uQ8mN;k%AkI3i@E_@kxuq&F^)Ee0PS-^ z9?T0bW=Asgv=l~pFRKxEY4Uh0C)vJCWx>~3>Dvud879oTzo6yeDIJ3cKm3_CD((JU z!NaOwuEgXKli|_b6CGUbU$3CXz}#6lg<;lg25J626DDRZUbYN2UOslGHfC174I4K( z1ctJ+PIE6_wMNl=&TJOz4XkXF3K>{ji@5eouj=hqJ@m@n1NGbiA|U2DcC zW(RZ*xF%m{JlXBxaNnMxuI5GC0-*!Z6(KC@G9E0d4hOh=62G>|@c0HyZ@#A!!RRF7 zSJ+Xhwd#$i|EX6D& Tz|8(n^kWR)p$LT}76xkoD9V^u diff --git a/blue_app_decred_testnet.gif b/blue_app_decred_testnet.gif deleted file mode 100644 index 901b21445b15f403f284f0c19b72f2f5d870502f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 817 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 ra5cBM9BBPmZ}SJ-`1CZ+NE3 From be6ffac2f861ffe0fe424777cfccc53eb842764a Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 27 Apr 2023 12:12:07 +0200 Subject: [PATCH 35/41] Allow custom snprintf formatting (H) --- Makefile | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index c476ed9..0ab0fdc 100755 --- a/Makefile +++ b/Makefile @@ -137,24 +137,13 @@ endif ############## # Compiler # ############## -ifneq ($(BOLOS_ENV),) -$(info BOLOS_ENV=$(BOLOS_ENV)) -CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/ -GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/ -else -$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH) -endif -ifeq ($(CLANGPATH),) -$(info CLANGPATH is not set: clang will be used from PATH) -endif -ifeq ($(GCCPATH),) -$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH) -endif CC := $(CLANGPATH)clang #CFLAGS += -O0 CFLAGS += -O3 -Os +# Remove warning on custom snprintf implementation usage +CFLAGS += -Wno-format AS := $(GCCPATH)arm-none-eabi-gcc From 0def8c728faccf5d2c0f5018508313a9477bdf18 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Thu, 27 Apr 2023 12:12:33 +0200 Subject: [PATCH 36/41] Static analysis fixes. --- .gitignore | 2 +- src/ui/ui_pubkey_bagl.c | 8 ++++---- src/ui/ui_shared.c | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index c9e6667..4017437 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ obj build test/__pycache__ test/snapshots-tmp -scan-build \ No newline at end of file +scan-build diff --git a/src/ui/ui_pubkey_bagl.c b/src/ui/ui_pubkey_bagl.c index b1e0041..079d569 100644 --- a/src/ui/ui_pubkey_bagl.c +++ b/src/ui/ui_pubkey_bagl.c @@ -56,7 +56,7 @@ UX_STEP_NOCB(ux_display_public_flow_5_step, bnnn_paging, { .title = "Address", - .text = G_io_apdu_buffer + 200, + .text = (const char *) G_io_apdu_buffer + 200, }); UX_STEP_VALID(ux_display_public_flow_6_step, pb, @@ -118,7 +118,7 @@ UX_STEP_VALID(ux_display_token_flow_1_step, { &C_icon_validate_14, "Confirm token", - G_io_apdu_buffer + 200, + (const char *) G_io_apdu_buffer + 200, }); UX_STEP_VALID(ux_display_token_flow_2_step, pb, @@ -130,9 +130,9 @@ UX_STEP_VALID(ux_display_token_flow_2_step, UX_FLOW(ux_display_token_flow, &ux_display_token_flow_1_step, &ux_display_token_flow_2_step); -void ui_display_public_key(unsigned char* derivation_path) { +void ui_display_public_key(unsigned char *derivation_path) { // append a white space at the end of the address to avoid glitch on nano S - strcat((char*) G_io_apdu_buffer + 200, " "); + strlcat((char *) G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); bip32_print_path(derivation_path, vars.tmp_warning.derivation_path, diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index e2fac74..fd55406 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -180,9 +180,9 @@ uint8_t prepare_single_output() { char tmp[80]; unsigned int offset = 0; unsigned char versionSize; - int addressOffset; + int addressOffset = 0; unsigned char address[22]; - unsigned short version; // addr prefix, or net id + unsigned short version = 0; // addr prefix, or net id unsigned short textSize; unsigned char script_version[2]; // Decred thing @@ -224,7 +224,7 @@ uint8_t prepare_single_output() { 1); tmp[textSize] = '\0'; - strcpy(vars.tmp.fullAddress, tmp); + strlcpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress)); } // Prepare amount @@ -362,7 +362,6 @@ uint8_t prepare_full_output(uint8_t checkOnly) { // Format validation message currentPos = 0; offset = 1; - btchip_context_D.tmp = (unsigned char *) tmp; for (i = 0; i < numberOutputs; i++) { if (!btchip_output_script_is_op_return(btchip_context_D.currentOutput + offset + 8 + 2)) { @@ -407,7 +406,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) { 1); tmp[textSize] = '\0'; - strcpy(vars.tmp.fullAddress, tmp); + strlcpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress)); // Prepare amount PRINTF("prepare amount\n"); From 97be02858e36b524123c87bccb1403a891435439 Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Mon, 12 Jun 2023 17:42:03 +0200 Subject: [PATCH 37/41] PR review --- .github/workflows/guidelines_enforcer.yml | 2 +- Makefile | 224 ++++++------------ src/btchip_apdu_get_firmware_version.c | 6 +- src/btchip_transaction.c | 6 - src/main.c | 104 +------- src/ui/ui_main_menu_bagl.c | 4 - src/ui/ui_main_menu_nbgl.c | 9 +- src/ui/ui_shared.c | 3 - src/ui/ui_shared.h | 3 - src/ui/ui_transaction_bagl.c | 4 +- src/ui/ui_transaction_nbgl.c | 84 +++---- .../test_1to2_warning_finalize_1/00000.png | Bin 343 -> 365 bytes .../test_1to2_warning_finalize_2/00000.png | Bin 350 -> 373 bytes .../test_1to2_warning_finalize_1/00000.png | Bin 389 -> 413 bytes .../test_1to2_warning_finalize_2/00000.png | Bin 397 -> 416 bytes .../test_1to2_warning_finalize_1/00000.png | Bin 389 -> 413 bytes .../test_1to2_warning_finalize_2/00000.png | Bin 397 -> 416 bytes .../stax/test_1to2_get_pubkey/00002.png | Bin 9215 -> 10347 bytes .../test_1to2_hash_input_finalize/00000.png | Bin 8176 -> 8201 bytes .../test_1to2_hash_input_finalize/00001.png | Bin 15536 -> 15555 bytes .../test_1to2_hash_input_finalize/00002.png | Bin 8545 -> 8724 bytes .../test_1to2_hash_input_finalize/00004.png | Bin 9215 -> 10347 bytes .../stax/test_1to2_warning_finalize/00001.png | Bin 8207 -> 8229 bytes .../stax/test_1to2_warning_finalize/00002.png | Bin 13653 -> 13679 bytes .../stax/test_1to2_warning_finalize/00003.png | Bin 8484 -> 8504 bytes .../stax/test_1to2_warning_finalize/00004.png | Bin 8179 -> 8203 bytes .../stax/test_1to2_warning_finalize/00005.png | Bin 13310 -> 13331 bytes .../stax/test_1to2_warning_finalize/00006.png | Bin 8484 -> 8504 bytes .../stax/test_1to2_warning_finalize/00007.png | Bin 8078 -> 8101 bytes .../stax/test_1to2_warning_finalize/00008.png | Bin 7702 -> 7723 bytes .../stax/test_1to2_warning_finalize/00009.png | Bin 8545 -> 8724 bytes .../stax/test_1to2_warning_finalize/00010.png | Bin 0 -> 5086 bytes .../stax/test_2to2_finalize_1/00000.png | Bin 8176 -> 8201 bytes .../stax/test_2to2_finalize_1/00001.png | Bin 15571 -> 15593 bytes .../stax/test_2to2_finalize_1/00002.png | Bin 8545 -> 8724 bytes .../stax/test_2to2_finalize_1/00004.png | Bin 9215 -> 10347 bytes .../stax/test_2to2_finalize_1/00005.png | Bin 0 -> 10347 bytes .../stax/test_2to2_finalize_1/00006.png | Bin 0 -> 10347 bytes .../stax/test_decred_sign_message/00000.png | Bin 8207 -> 8114 bytes .../stax/test_decred_sign_message/00001.png | Bin 12743 -> 12651 bytes .../stax/test_decred_sign_message/00002.png | Bin 8557 -> 8724 bytes .../stax/test_decred_sign_message/00004.png | Bin 9215 -> 10347 bytes test/test_1to2_warning_change.py | 14 +- 43 files changed, 129 insertions(+), 334 deletions(-) create mode 100644 test/snapshots/stax/test_1to2_warning_finalize/00010.png create mode 100644 test/snapshots/stax/test_2to2_finalize_1/00005.png create mode 100644 test/snapshots/stax/test_2to2_finalize_1/00006.png diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml index a72f8e0..9b3b6dd 100644 --- a/.github/workflows/guidelines_enforcer.yml +++ b/.github/workflows/guidelines_enforcer.yml @@ -11,5 +11,5 @@ on: jobs: guidelines_enforcer: - name: Guidelines_enforcer + name: Call Ledger guidelines_enforcer uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1 diff --git a/Makefile b/Makefile index 0ab0fdc..7a7c10d 100755 --- a/Makefile +++ b/Makefile @@ -1,182 +1,110 @@ -#******************************************************************************* -# Ledger App -# (c) 2017 Ledger +# **************************************************************************** +# Decred Ledger App +# (c) 2023 Ledger SAS. # -# 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 +# 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 +# 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. -#******************************************************************************* +# 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. +# **************************************************************************** ifeq ($(BOLOS_SDK),) $(error Environment variable BOLOS_SDK is not set) endif + include $(BOLOS_SDK)/Makefile.defines -APP_PATH = "44'/42'" -# All but Decred app use dependency onto the decred app/lib -DEFINES_LIB = USE_LIB_DECRED +######################################## +# Mandatory configuration # +######################################## + +# Enabling DEBUG flag will enable PRINTF and disable optimizations +#DEBUG = 1 + +# Application version +APPVERSION_M= 1 +APPVERSION_N= 3 +APPVERSION_P= 13 +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" + +# Application source files +APP_SOURCE_PATH += src -APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) +# Application icons +ICON_NANOS = nanos_app_$(COIN).gif +ICON_STAX = stax_app_$(COIN).gif +ICON_NANOX = nanox_app_$(COIN).gif +ICON_NANOSP = nanox_app_$(COIN).gif -APPVERSION_M=1 -APPVERSION_N=3 -APPVERSION_P=13 -APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) -APP_LOAD_FLAGS=--appFlags 0x250 +# Application allowed derivation curves. +CURVE_APP_LOAD_PARAMS = secp256k1 + +# Application allowed derivation paths. +PATH_APP_LOAD_PARAMS = "44'/42'" + +# Setting to allow building variant applications +VARIANT_PARAM = COIN +VARIANT_VALUES = decred decred_testnet -# simplify for tests ifndef COIN COIN=decred endif +######################################## +# Application custom permissions # +######################################## +# See SDK `include/appflags.h` for the purpose of each permission +HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1 +HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 +HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1 + ifeq ($(COIN),decred) # Decred mainnet -DEFINES += COIN_P2PKH_VERSION=1855 COIN_P2SH_VERSION=1818 COIN_FAMILY=1 COIN_COINID=\"Decred\" COIN_COINID_HEADER=\"DECRED\" COIN_COLOR_HDR=0x5482ff COIN_COLOR_DB=0xB2E8CB COIN_COINID_NAME=\"Decred\" COIN_COINID_SHORT=\"DCR\" COIN_KIND=COIN_KIND_DECRED -APPNAME ="Decred" -APP_LOAD_PARAMS += --path $(APP_PATH) -DEFINES_LIB =# Decred IS the lib -APP_LOAD_FLAGS=--appFlags 0xa50 +DEFINES_LIB = # Decred IS the lib +DEFINES += COIN_P2PKH_VERSION=1855 COIN_P2SH_VERSION=1818 COIN_FAMILY=1 COIN_COINID=\"Decred\" COIN_COINID_HEADER=\"DECRED\" COIN_COLOR_HDR=0x5482ff COIN_COLOR_DB=0xB2E8CB COIN_COINID_NAME=\"Decred\" COIN_COINID_SHORT=\"DCR\" COIN_KIND=COIN_KIND_DECRED +APPNAME = "Decred" +HAVE_APPLICATION_FLAG_LIBRARY = 1 else ifeq ($(COIN),decred_testnet) # Decred testnet -DEFINES += COIN_P2PKH_VERSION=3873 COIN_P2SH_VERSION=3836 COIN_FAMILY=1 COIN_COINID=\"Decred\" COIN_COINID_HEADER=\"DECRED\" COIN_COLOR_HDR=0x5482ff COIN_COLOR_DB=0xB2E8CB COIN_COINID_NAME=\"Decred\" COIN_COINID_SHORT=\"TDCR\" COIN_KIND=COIN_KIND_DECRED_TESTNET -APPNAME ="Decred Test" -APP_LOAD_PARAMS += --path $(APP_PATH) - +# All but Decred app use dependency onto the decred app/lib +DEFINES_LIB = USE_LIB_DECRED +DEFINES += COIN_P2PKH_VERSION=3873 COIN_P2SH_VERSION=3836 COIN_FAMILY=1 COIN_COINID=\"Decred\" COIN_COINID_HEADER=\"DECRED\" COIN_COLOR_HDR=0x5482ff COIN_COLOR_DB=0xB2E8CB COIN_COINID_NAME=\"Decred\" COIN_COINID_SHORT=\"TDCR\" COIN_KIND=COIN_KIND_DECRED_TESTNET +APPNAME = "Decred Test" else ifeq ($(filter clean,$(MAKECMDGOALS)),) $(error Unsupported COIN - use decred, decred_testnet) endif endif -APP_LOAD_PARAMS += $(APP_LOAD_FLAGS) -DEFINES += $(DEFINES_LIB) +DEFINES += $(DEFINES_LIB) TCS_LOADER_PATCH_VERSION=0 -ifeq ($(TARGET_NAME),TARGET_NANOS) -ICONNAME=nanos_app_$(COIN).gif -else ifeq ($(TARGET_NAME),TARGET_STAX) -ICONNAME=stax_app_$(COIN).gif -else -ICONNAME=nanox_app_$(COIN).gif -endif - -################ -# Default rule # -################ -all: default - -############ -# Platform # -############ - -DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300 -DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U -DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU -DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) TCS_LOADER_PATCH_VERSION=0 - -# U2F -DEFINES += HAVE_U2F HAVE_IO_U2F -DEFINES += U2F_PROXY_MAGIC=\"BTC\" -DEFINES += USB_SEGMENT_SIZE=64 -DEFINES += BLE_SEGMENT_SIZE=32 #max MTU, min 20 - -#WEBUSB_URL = www.ledgerwallet.com -#DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g") -DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" - -DEFINES += UNUSED\(x\)=\(void\)x -DEFINES += APPVERSION=\"$(APPVERSION)\" - -ifeq ($(TARGET_NAME),TARGET_STAX) - DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 - DEFINES += NBGL_QRCODE NBGL_USE_CASE NBGL_PAGE -else - DEFINES += HAVE_BAGL HAVE_UX_FLOW -endif - -# BLE -ifeq ($(TARGET_NAME),TARGET_NANOX) -DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU -else ifeq ($(TARGET_NAME),TARGET_STAX) -DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU -endif - -ifneq ($(TARGET_NAME),TARGET_NANOS) -DEFINES += HAVE_GLO096 -ifneq ($(TARGET_NAME),TARGET_STAX) -DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 -endif -DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature -DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -endif - -# Enabling debug PRINTF -DEBUG = 0 -ifneq ($(DEBUG),0) - - ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += HAVE_PRINTF PRINTF=screen_printf - else - DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf - endif -else - DEFINES += PRINTF\(...\)= -endif - - - -############## -# Compiler # -############## - -CC := $(CLANGPATH)clang - -#CFLAGS += -O0 -CFLAGS += -O3 -Os # Remove warning on custom snprintf implementation usage -CFLAGS += -Wno-format - -AS := $(GCCPATH)arm-none-eabi-gcc +CFLAGS += -Wno-format -LD := $(GCCPATH)arm-none-eabi-gcc -LDFLAGS += -O3 -Os -LDLIBS += -lm -lgcc -lc - -# import rules to compile glyphs(/pone) -include $(BOLOS_SDK)/Makefile.glyphs - -### variables processed by the common makefile.rules of the SDK to grab source files and include dirs -APP_SOURCE_PATH += src +# U2F +DEFINES += HAVE_IO_U2F U2F_PROXY_MAGIC=\"BTC\" SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f -ifneq ($(TARGET_NAME),TARGET_STAX) -SDK_SOURCE_PATH += lib_ux -endif - -ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) -SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -endif - -load: all - python -m ledgerblue.loadApp $(APP_LOAD_PARAMS) - -delete: - python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS) +######################################## +# Application communication interfaces # +######################################## +ENABLE_BLUETOOTH = 1 -# import generic rules from the sdk -include $(BOLOS_SDK)/Makefile.rules +######################################## +# NBGL custom features # +######################################## +ENABLE_NBGL_QRCODE = 1 -#add dependency on custom makefile filename -dep/%.d: %.c Makefile +# Use only specific files from standard app +DISABLE_STANDARD_APP_FILES = 1 +APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/io.c +INCLUDES_PATH += ${BOLOS_SDK}/lib_standard_app -listvariants: - @echo VARIANTS COIN decred decred_testnet +include $(BOLOS_SDK)/Makefile.standard_app \ No newline at end of file diff --git a/src/btchip_apdu_get_firmware_version.c b/src/btchip_apdu_get_firmware_version.c index a75d104..6a3bb5a 100644 --- a/src/btchip_apdu_get_firmware_version.c +++ b/src/btchip_apdu_get_firmware_version.c @@ -34,9 +34,9 @@ void get_firmware_version(unsigned char *buffer) { buffer[0] = ARCH_ID; - buffer[1] = LEDGER_MAJOR_VERSION; - buffer[2] = LEDGER_MINOR_VERSION; - buffer[3] = LEDGER_PATCH_VERSION; + buffer[1] = MAJOR_VERSION; + buffer[2] = MINOR_VERSION; + buffer[3] = PATCH_VERSION; buffer[4] = 1; buffer[5] = TCS_LOADER_PATCH_VERSION; } diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index c3bdd59..ae73f82 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -19,8 +19,6 @@ #include "btchip_apdu_constants.h" #include "blake256.h" -// #define DEBUG_LONG "%ld" - #define DEBUG_LONG "%d" void check_transaction_available(unsigned char x) { @@ -182,7 +180,6 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - // no break is intentional __attribute__((fallthrough)); } @@ -356,7 +353,6 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - // no break is intentional __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { @@ -438,7 +434,6 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - // no break is intentional __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { @@ -481,7 +476,6 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; - // no break is intentional __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { diff --git a/src/main.c b/src/main.c index fb26e1d..feaa720 100644 --- a/src/main.c +++ b/src/main.c @@ -27,6 +27,8 @@ #include "ux.h" +#include "io.h" + #include "ui_main_menu.h" #include "ui_pubkey.h" #include "ui_shared.h" @@ -38,27 +40,12 @@ bagl_element_t tmp_element; #endif -unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; - -#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10 -#define BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH 8 -#define MAX_CHAR_PER_LINE 25 - -#define COLOR_BG_1 0xF9F9F9 -#define COLOR_APP COIN_COLOR_HDR // bitcoin 0xFCB653 -#define COLOR_APP_LIGHT COIN_COLOR_DB // bitcoin 0xFEDBA9 -#define COLOR_BLACK 0x000000 - -#define COLOR_GRAY 0x999999 -#define COLOR_LIGHT_GRAY 0xEEEEEE - #ifndef TARGET_STAX unsigned int io_seproxyhal_touch_settings(const bagl_element_t *e); unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e); #endif void ui_idle(void); -#include "ux.h" ux_state_t G_ux; bolos_ux_params_t G_ux_params; @@ -71,89 +58,6 @@ void io_seproxyhal_display(const bagl_element_t *element) { } #endif -unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); - } - - default: - THROW(INVALID_PARAMETER); - } - return 0; -} - -unsigned char io_event(unsigned char channel) { - UNUSED(channel); - // nothing done with the event, throw an error on the transport layer if - // needed - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; - -#ifndef TARGET_STAX - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; -#endif - - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - // no break is intentional - __attribute__((fallthrough)); - default: - UX_DEFAULT_EVENT(); - break; -#ifndef TARGET_STAX - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; -#endif - - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { - // don't redisplay if UX not allowed (pin locked in the common bolos - // ux ?) - if (ux_step_count && UX_ALLOWED) { - // prepare next screen - if (!ux_loop_over_curr_element) { - ux_step = (ux_step + 1) % ux_step_count; - } - // redisplay screen - UX_REDISPLAY(); - } - }); - break; - } - - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - // command has been processed, DO NOT reset the current APDU transport - return 1; -} - void app_exit(void) { BEGIN_TRY_L(exit) { TRY_L(exit) { @@ -243,10 +147,10 @@ __attribute__((section(".boot"))) int main(int arg0) { TRY { io_seproxyhal_init(); -#ifdef TARGET_NANOX +#ifdef HAVE_BLE // grab the current plane mode setting G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX +#endif // HAVE_BLE btchip_context_init(); diff --git a/src/ui/ui_main_menu_bagl.c b/src/ui/ui_main_menu_bagl.c index b427a79..3feff51 100644 --- a/src/ui/ui_main_menu_bagl.c +++ b/src/ui/ui_main_menu_bagl.c @@ -24,8 +24,6 @@ #include "btchip_internal.h" -// #include "btchip_bagl_extensions.h" - const char* settings_submenu_getter(unsigned int idx); void settings_submenu_selector(unsigned int idx); @@ -122,8 +120,6 @@ UX_FLOW(ux_idle_flow, &ux_idle_flow_4_step); void ui_idle(void) { - ux_step_count = 0; - ux_loop_over_curr_element = 0; // reserve a display stack slot if none yet if (G_ux.stack_count == 0) { ux_stack_push(); diff --git a/src/ui/ui_main_menu_nbgl.c b/src/ui/ui_main_menu_nbgl.c index b105c82..0afbd9a 100644 --- a/src/ui/ui_main_menu_nbgl.c +++ b/src/ui/ui_main_menu_nbgl.c @@ -50,7 +50,7 @@ static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content) { setting_switch.subText = "Enable automatic key export"; setting_switch.token = SWITCH_KEY_EXPORT_TOKEN; setting_switch.tuneId = TUNE_TAP_CASUAL; - + setting_switch.initState = (bool) !N_btchip.pubKeyRequestRestriction; content->type = SWITCHES_LIST; content->switchesList.nbSwitches = 1; content->switchesList.switches = (nbgl_layoutSwitch_t *) &setting_switch; @@ -69,10 +69,8 @@ static void settingsControlsCallback(int token, uint8_t index) { UNUSED(index); switch (token) { case SWITCH_KEY_EXPORT_TOKEN: - setting_switch.initState = !setting_switch.initState; unsigned int setting_value = (unsigned int) !setting_switch.initState; nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &setting_value, 1); - displaySettingsMenu(); break; default: PRINTF("Should not happen !"); @@ -84,17 +82,16 @@ static void displaySettingsMenu(void) { nbgl_useCaseSettings("Stellar settings", 0, 2, - true, + false, ui_idle, settingsNavCallback, settingsControlsCallback); } void ui_idle(void) { - setting_switch.initState = (bool) !N_btchip.pubKeyRequestRestriction; nbgl_useCaseHome("Decred", &C_decred_icon_64px, - "This app confirms actions on\nthe Decred network.", + NULL, true, displaySettingsMenu, onQuitCallback); diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index fd55406..31f46b8 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -22,9 +22,6 @@ #include "btchip_bcd.h" #include "ui_main_menu.h" -unsigned int ux_step; -unsigned int ux_step_count; -uint8_t ux_loop_over_curr_element; vars_u_t vars; unsigned int io_seproxyhal_touch_display_cancel(const void *e) { diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index e9ae799..8ed6950 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -81,9 +81,6 @@ typedef union { } vars_u_t; extern vars_u_t vars; -extern unsigned int ux_step; -extern unsigned int ux_step_count; -extern uint8_t ux_loop_over_curr_element; unsigned int io_seproxyhal_touch_display_cancel(const void *e); unsigned int io_seproxyhal_touch_display_ok(const void *e); diff --git a/src/ui/ui_transaction_bagl.c b/src/ui/ui_transaction_bagl.c index 5e1d968..7fee449 100644 --- a/src/ui/ui_transaction_bagl.c +++ b/src/ui/ui_transaction_bagl.c @@ -112,7 +112,7 @@ UX_FLOW(ux_confirm_full_flow, UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, - {&C_icon_eye, "Confirm output", vars.tmp.feesAmount}); + {&C_icon_eye, "Review output", vars.tmp.feesAmount}); UX_STEP_NOCB(ux_confirm_single_flow_2_step, bnnn_paging, { @@ -139,7 +139,7 @@ UX_STEP_VALID(ux_confirm_single_flow_5_step, &C_icon_crossmark, "Reject", }); -// confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: fullAddress +// confirm_single: review output #x(feesAmount) / Amount: fullAmount / Address: fullAddress UX_FLOW(ux_confirm_single_flow, &ux_confirm_single_flow_1_step, &ux_confirm_single_flow_2_step, diff --git a/src/ui/ui_transaction_nbgl.c b/src/ui/ui_transaction_nbgl.c index 84ea59e..4207312 100644 --- a/src/ui/ui_transaction_nbgl.c +++ b/src/ui/ui_transaction_nbgl.c @@ -38,11 +38,7 @@ typedef enum { typedef struct { const char* reviewStart; - const char* reviewCancel; const char* finishOk; - const char* finishCancel; - const char* choiceCancel; - const char* choiceGoBack; } messages_t; static nbgl_layoutTagValueList_t pairList; @@ -51,28 +47,12 @@ static nbgl_pageInfoLongPress_t infoLongPress; static transaction_type_t txType; static messages_t msgs; static char genericText[70]; -static bool reviewStarted; static void reviewChoice(bool confirm); -static void rejectChoice(bool confirm); -static void rejectUseCaseChoice(void); +static void rejectChoice(void); static void displayTransaction(void); static void reviewStart(void); -static void rejectChoice(bool confirm) { - if (confirm) { - nbgl_useCaseStatus(msgs.finishCancel, true, ui_idle); - txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_cancel(NULL) - : io_seproxyhal_touch_verify_cancel(NULL); - } else { - if (reviewStarted) { - displayTransaction(); - } else { - reviewStart(); - } - } -} - static void reviewChoice(bool confirm) { if (confirm) { if (txType != TX_TYPE_SINGLE_OUTPUT) { @@ -81,22 +61,26 @@ static void reviewChoice(bool confirm) { txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_ok(NULL) : io_seproxyhal_touch_verify_ok(NULL); } else { - rejectUseCaseChoice(); + rejectChoice(); } } -static void rejectUseCaseChoice(void) { - nbgl_useCaseChoice(NULL, - msgs.choiceCancel, - NULL, - "Yes, cancel", - msgs.choiceGoBack, - rejectChoice); +static void rejectConfirmation(void) { + nbgl_useCaseStatus("Transaction rejected", false, ui_idle); + txType == TX_TYPE_SIGN_MESSAGE ? io_seproxyhal_touch_message_signature_verify_cancel(NULL) + : io_seproxyhal_touch_verify_cancel(NULL); +} + +static void rejectChoice(void) { + nbgl_useCaseConfirm("Reject transaction ?", + NULL, + "Yes, Reject", + "Go back to transaction", + rejectConfirmation); } static void displayTransaction(void) { - reviewStarted = true; - nbgl_useCaseStaticReview(&pairList, &infoLongPress, msgs.reviewCancel, reviewChoice); + nbgl_useCaseStaticReview(&pairList, &infoLongPress, "Reject transaction", reviewChoice); } static void reviewStart(void) { @@ -104,27 +88,20 @@ static void reviewStart(void) { explicit_bzero(&infoLongPress, sizeof(infoLongPress)); msgs.reviewStart = "Review\ntransaction"; - msgs.reviewCancel = "Cancel transaction"; - msgs.choiceCancel = "Cancel transaction ?"; - msgs.choiceGoBack = "Go back to transaction"; msgs.finishOk = "TRANSACTION\nSIGNED"; - msgs.finishCancel = "Transaction rejected"; - infoLongPress.text = "Accept and send"; - infoLongPress.longPressText = "Hold to accept"; + infoLongPress.text = "Sign transaction"; + infoLongPress.longPressText = "Hold to sign"; infoLongPress.icon = &C_decred_icon_64px; - pairs[0].item = "Amount"; - pairs[0].value = vars.tmp.fullAmount; - pairs[1].item = "To"; - pairs[1].value = vars.tmp.fullAddress; - pairs[2].item = "Fees"; - pairs[2].value = vars.tmp.feesAmount; - pairList.nbPairs = 3; pairList.pairs = (nbgl_layoutTagValue_t*) pairs; switch (txType) { case TX_TYPE_SINGLE_OUTPUT: + pairs[0].item = "Amount"; + pairs[0].value = vars.tmp.fullAmount; + pairs[1].item = "To"; + pairs[1].value = vars.tmp.fullAddress; pairList.nbPairs = 2; explicit_bzero(genericText, sizeof(genericText)); snprintf(genericText, @@ -147,26 +124,27 @@ static void reviewStart(void) { pairs[0].value = vars.tmp.fullAddress; pairList.nbPairs = 1; msgs.reviewStart = "Sign\nMessage"; - msgs.reviewCancel = "Cancel signature"; - msgs.choiceCancel = "Cancel signature ?"; - msgs.choiceGoBack = "Go back to signature"; msgs.finishOk = "MESSAGE SIGNED"; - msgs.finishCancel = "SIGNATURE\nCANCELLED"; - infoLongPress.text = "Sign message"; - infoLongPress.longPressText = "Hold to sign"; break; case TX_TYPE_FULL_REVIEW: + __attribute__((fallthrough)); default: + pairs[0].item = "Amount"; + pairs[0].value = vars.tmp.fullAmount; + pairs[1].item = "To"; + pairs[1].value = vars.tmp.fullAddress; + pairs[2].item = "Fees"; + pairs[2].value = vars.tmp.feesAmount; + pairList.nbPairs = 3; break; } - reviewStarted = false; nbgl_useCaseReviewStart(&C_decred_icon_64px, msgs.reviewStart, NULL, - msgs.reviewCancel, + "Reject transaction", displayTransaction, - rejectUseCaseChoice); + rejectChoice); } unsigned int ui_tx_confirm_full_output() { diff --git a/test/snapshots/nanos/test_1to2_warning_finalize_1/00000.png b/test/snapshots/nanos/test_1to2_warning_finalize_1/00000.png index c9797d57b1712ba65bac9439b387f976fda4dc03..37543fdb58532d1a7a163b2c9111739c843d1f78 100644 GIT binary patch delta 338 zcmV-Y0j>Vm0__5jB!4tXL_t(|ob8$04uc>JhIN_m|G-}8g^TNeRtj}g_`fU$87+rW zs4z_c002g1Ze0Jie$(@!6I7K4X{Z5c+7D%|%9eVSX#WG-`uR;!XW~q*uxwo_#g#vw zG@+GpO|mB@iTIgc?`5V+O5~kc?nchG(luQ*cOEd&SR5GO7=QO*5LFxOlXv540~Cib z0rMgSHpjo2RZvy3S_f1ZfLmDWdwULdjy6@{OR3~)M*CGJWltOoaG5<(-?d0XT^Jge z*RiL2fqGs!aUd+b_Jmcxh#s#WVm`5QaRWc#rg_KH-w-noNFEXZncuLu;xv>S?qWZs zExR{{Ylr&j{pDw delta 316 zcmV-C0mJ_70@nhNB!3=BL_t(|ob8#*5`!QNMWIvw|ASf31yfoB0ZmXCbI%IV5C-xf z=o|n50IT@f6L2nuU)yg&@gx|7WCYX1u-gEE`2EO~GE%cWfV0^=-Tbz6lxh!o+5Ul3IwWUHo_EcDJ+paYIn7R6Nx$uWB#24Q#+<-hbKw^wG`s(M7QVTo^sI znkhk%?AK0}7r`lQWT`UYAD7B%WwY&QwPVq0_toV9qT9~8YZy?wkm{-Z_-xcg8BReu zWKK^?GYOoTn=*ef!#sd1L_vdn-d5ZNamy`E#pDV_Gt{z-FM3kU(L|o|wj?!d_|pQn zp@iz4BDfIF-ZgD_0FI%PnYsZvb65)ci*fJ|$#YpI1R>u700000SmFaaHq6M#ycfCv O0000nD;)h+cH(f$Ya?fnZyXUa^jaC>&C6jwey zX+kPxnrcr}66LeM-os3hRFh|CxgV0+O4oFe?OednSPV=+9Dnz05Jex@D}RlrCtx^? z$ynA_U=!bVRzX#@)f!-80=R{BzPD+(d$frPA4*kMGup2)DSgUdfXnp6eAfyMb75#U zy@oyA3e@w)DFflgUr%WDi|Dbs5wnSwi!1m6XXcL0UlBDAs2&o4Hs4|K#Azru+{1pF zS~d_?UIqP4NmKQFN~$4Cl&}0^={_KmZE*ZKfjPJXOD@wFhQrW%nE$CuP-FeM$LJg2 s@ZQ5a2JQnQnY}xXL;(N*002M;FT7IvD|egNr2qf`07*qoM6N<$f=8vI!2kdN delta 323 zcmV-J0lfb80^S0UB!4AIL_t(|ob8#*62l+}MNOyq{}0Y0T{yKZ5lp~F2ku#=CWxav zgr)=l03a&M=mn&-Z=dI7Rf=c9ebdYkntl5@0EPJd=#(;2qdkDL*|Oa7_UI_p5%OwT z>1W58Wu@eqo9&X+L{#nKd$2q=2b&)Yf@-DerM`JoN5O620DlJav`%1;Zn3W}h6CWj z=%wAv35sMtIaU4%PN|TkjtT#~R8gy2Z9{7ui#EHjEe8pQG0cBx2omB?jNPAr=D!@?F}I_8LG0b}O%wnC0001_^a6&! V%I8RTVIcqj002ovPDHLkV1m(AoS6Us diff --git a/test/snapshots/nanosp/test_1to2_warning_finalize_1/00000.png b/test/snapshots/nanosp/test_1to2_warning_finalize_1/00000.png index de029b12ae8224f7134b863b231eec0fabdbf8b7..a9bece95e2d0414bb1f605346fc7f5a112ff7734 100644 GIT binary patch delta 386 zcmV-|0e$|31DykqB!6T{L_t(|obB3Sj)Nc&hGDwtO}PJ&<}Ulg#7tnc1*P<(@AIRf zt_TjIcG#2v000000Prgwvpdkw%=U85d16nlkQ@LXdQWi}^afy$z7Kb}QNrKs4sc(^Nhx%MD$WMzflT#;_!|h?Yu64Bk{^<*?wJypz54<$P zGr6Tuf4<-D%Z*L7F7k(Z-gVHhfpFEZ=?LpFGar^A1F$tv1hFY!wrX;%h<+OS3^>2j zZGWvhbh7idr+Y8Usk=R7280cV_oeGQzpQn%e3q)2+EfeonEtR)U6Nb|0{{TfRHu(7 zcBYTyLpV$XiN2oe{a;WW{XO)$!yx9Jgs2M1ThL0x2B27_QM}~kove^3j)&L`@Oa(= g00000003z450H>ZThov^6951J07*qoM6N<$f^EgSod5s; delta 362 zcmV-w0hRup1BC;SB!5gvL_t(|obB3M4uc>RMN!&xCd_|GcP{-fA%vHTP&{_8FKdg? z3&=yA0{{R3006+hc&#o#KQjx*-us0mxk9o6;?Tzwt3j^5 zE!vID`fC@rVwOa_yP*usci2kU%!B_NjoM%I`cQE8xLXmr?Tj{%7E&007XW{$8RJ9fXVfKccg8z4wCh=odFHG0|2B z?R`)clDD8I5vzbO($+cwraSm3Muk`ph%w#*000000021Q3qsZzE;C$(UH||907*qo IM6N<$f=9)tNdN!< diff --git a/test/snapshots/nanosp/test_1to2_warning_finalize_2/00000.png b/test/snapshots/nanosp/test_1to2_warning_finalize_2/00000.png index 2e267527ba5e37d65ad5f4f9e3fd0e050017666c..45c5c336e6c2a271cb568e06dd1baae3b1dfbb8b 100644 GIT binary patch delta 389 zcmV;00eb$81E2$tB!6c~L_t(|obB3S5`rKQhGA;D3HLwJ-lZSTI6HtCDAK3z^P?dX z!3E6LLI3~&0002MQ@mz(pr4to(j~6+^$!y9)~3hW?3r{C^Mw0001nyW$6PP~%LVymQOxAziRI$e?0unZZ1rGX@fP5H9BCfAbahoRpA^()=- zY2KmA&dZ*@EPf~N_K+1&Y`Az`I==I6t*ysrAzP_UwQ!E>Wt zW=X2#XXM5}?=C1$XU^`?^Hf4FHy(N`ph7W6B=*k;a^iA5{yjE00000NkvXXu0mjfy2-nG delta 370 zcmV-&0ge8k1C0ZaB!5&%L_t(|obB3M4uc>Ng<;!tC+vSovzI=Y7{X19gLv%!JyBbQ z4k$O51poj500030;x)Sf{mg7jhY%)~)R1OjB#-ip_t~y#tb1D~5ihHws!9hTg<8CVyf8006*nV<(Ij={|i+ zyB6(6M*X#uOEFU--rZ0f^L3jEn^|!>ns1flGuYyhc(^Nhx%MD$WMzflT#;_!|h?Yu64Bk{^<*?wJypz54<$P zGr6Tuf4<-D%Z*L7F7k(Z-gVHhfpFEZ=?LpFGar^A1F$tv1hFY!wrX;%h<+OS3^>2j zZGWvhbh7idr+Y8Usk=R7280cV_oeGQzpQn%e3q)2+EfeonEtR)U6Nb|0{{TfRHu(7 zcBYTyLpV$XiN2oe{a;WW{XO)$!yx9Jgs2M1ThL0x2B27_QM}~kove^3j)&L`@Oa(= g00000003z450H>ZThov^6951J07*qoM6N<$f^EgSod5s; delta 362 zcmV-w0hRup1BC;SB!5gvL_t(|obB3M4uc>RMN!&xCd_|GcP{-fA%vHTP&{_8FKdg? z3&=yA0{{R3006+hc&#o#KQjx*-us0mxk9o6;?Tzwt3j^5 zE!vID`fC@rVwOa_yP*usci2kU%!B_NjoM%I`cQE8xLXmr?Tj{%7E&007XW{$8RJ9fXVfKccg8z4wCh=odFHG0|2B z?R`)clDD8I5vzbO($+cwraSm3Muk`ph%w#*000000021Q3qsZzE;C$(UH||907*qo IM6N<$f=9)tNdN!< diff --git a/test/snapshots/nanox/test_1to2_warning_finalize_2/00000.png b/test/snapshots/nanox/test_1to2_warning_finalize_2/00000.png index 2e267527ba5e37d65ad5f4f9e3fd0e050017666c..45c5c336e6c2a271cb568e06dd1baae3b1dfbb8b 100644 GIT binary patch delta 389 zcmV;00eb$81E2$tB!6c~L_t(|obB3S5`rKQhGA;D3HLwJ-lZSTI6HtCDAK3z^P?dX z!3E6LLI3~&0002MQ@mz(pr4to(j~6+^$!y9)~3hW?3r{C^Mw0001nyW$6PP~%LVymQOxAziRI$e?0unZZ1rGX@fP5H9BCfAbahoRpA^()=- zY2KmA&dZ*@EPf~N_K+1&Y`Az`I==I6t*ysrAzP_UwQ!E>Wt zW=X2#XXM5}?=C1$XU^`?^Hf4FHy(N`ph7W6B=*k;a^iA5{yjE00000NkvXXu0mjfy2-nG delta 370 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 literal 9215 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 literal 8176 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 TV-DWr%Q!o^ovl9;^viz$-cC%N diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00001.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00001.png index f655aa02919b5df6f6794fe1f8988f85585b3359..5383011488ad3ab2a42e0643df01a478df6b5546 100644 GIT binary patch literal 15555 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 A@c;k- diff --git a/test/snapshots/stax/test_1to2_get_pubkey/00002.png b/test/snapshots/stax/test_1to2_get_pubkey/00002.png index 82497e000274af8643c9f7f7857adb7ae5bdad70..f59899e9aa967b23177d83aef0c8c2c9041eab91 100644 GIT binary patch literal 4615 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 diff --git a/test/snapshots/stax/test_1to2_get_pubkey/00003.png b/test/snapshots/stax/test_1to2_get_pubkey/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..30b434c51f5be56b80b57118f490c5428212d705 GIT binary patch literal 10937 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00000.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00000.png index f3c2cd88fd4d08fe8c4882caecee2d801038c85e..81651ed8aa4b9bea59d1226e0f71ac491f739b56 100644 GIT binary patch literal 8957 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 z%0D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 bU~dAk>~8X@C~M$vEkZU{c9*L!dO!RRxgBn~ literal 8201 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 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00001.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00001.png index 5383011488ad3ab2a42e0643df01a478df6b5546..8d17153b8e392f511e58b78f5ba93cd8e46df74b 100644 GIT binary patch literal 15594 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

@lzWX7nWbuh4}_9 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 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00002.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00002.png index ee463b619fd13d09cf916b998de1d5f07b74bffa..abb4b7834dd1dcd0d3d1089d562d4519837db08e 100644 GIT binary patch literal 9483 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 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00003.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00003.png index 7a05bf7b31c3fca94a4a464ad8709d1c20600e36..cd2f52759f160c3e2cf6822395ea675b8c84a851 100644 GIT binary patch delta 3463 zcmW-jc|g+H7RNI!#}<4!QuBRw|f?zpRuulW9G- z5|L~X!vz(S6orUUa{-!286_k$Awxt#Q5NO>-n)OFd+xdCp6};=$L)pt@7YCc{qdJ$ zN6uzd$wdmprzE!eT#i8aQ|;}DwP)6r-`E{*7HsBk_Uqcx?|1)f7J9SPg@b<(y;NG?Wd?lMn4*t+%Uqq6&ehPkeu{% z)ekC-O3K3xnXXzsbw-ag-`IY0-CzGY@O^KEoSj6q-Qe4YDSuHsW>~ZtDKRqIwYj%~ zaO#Wx$QvcJJTmz{%MxJpxQm!nPNHfAH!RyZb$(BFtDg^GLbr(O5^w;siPTiC~R!rUmnpIHkFqd!;`8yn@rdH z#p>i2i!Z-=rNDUGgx3#GT=BAoWX70pTFht@bVK!n*+BQIKhq)hT}4HOq@}pHn0>}+ z+nq!6H@M1Xu_B;IJ%h)uUk?uETsz*Y>G5;N|2MCZKb)_^ZQj) z9d?DlNkqm~aW8~-K{LJ?S*M6R>a;%jqvB;27Ap@lEH8UqYom^)#8+}Hlv?c=t@iEG zJz#0mi-TRC!UUP5NXys()S0@cES$?C1?_PELcY^P%#JSBeK- z60o$i zD;|L;yIUb<0_fU(8v`+O3GydRGHR6P?w82$Z=1F!^}ij>Eb(hBqws;aiJ3I)y!@p$ zkH_QLf!zzG@#i+_O}UOG`~78@5gcu23;d%IjkAmr8=wJ`ea(&J5Ob@JgV zhR>NatE9*RVs&)^@#-T9LAr8^wcj~dtoXG(|FD0zR{p4%ZN-QfwSei2!ZeZ$cq5s7 z0A@+sK;mC=m9l{e7s->BLu>}&q};LAe8<_44QJSOL%xSgH<(k&B8@jNi!8zUAMlm~ENwKxH4KZBd z0XD`yxt=3W7n#|k=iVdXgmNUz8e(p4?gy;u=O_C(9F9mNqQo%^JdcX~-ZSPsch*eu zHY{H=&f94~y$xvgWnb&)TA|_bcw4_*Hv`{8wuMv-r&DM-K9XH!_jO%XvPJDoO&O@+ zj_7f*SUf(i=15okSK7xr3*0{fL20H)vk`lkK1#)rysT!VpMld`2K@&Fli{tEeB-`A zJt!6Hp6t%z4p^aTW{ic~v-Ow3tEBiGF~GINGTKyp4}PG%`>T)O`qDec!7bZuxv?O?gZVyV%ih>q&d^?^>3z}>f%6sm7c9-Ut%76`ZvIogk?A-TonmfYgnDVfEY5;qoLXU zQ(c>8wvQi<$W$xW$jhGa6Xi>~*62*9mTQZlhBl`^(Aj^Np(IXD{lMV}wtoyoFhwG0 zqF4Smf=%<`w-BrJ>V>$#uOZ1>l6YO-a|;_>NcjC&&E9jB9PpQDP_3wKhcE?N>1T^a zoXpw5{LNNa2lvZ%fVhZ6B5B2AAtF@!Ns@E0v%cph^f=yOAieR zqXLaj{fxYS7^;`aWOKN%%owzdvbx5jz&XmhHVhcIXvmXxE_acfKlb2CiLvt_zeCKJ z1Zu!t;(kBq^>SrT$lH4IZxjItVG=J&u*m20bEBDxD*n=HjR(5YYvn^coWSVnDhwI2 zf54N9X!29_5F*EBR7hiHYuZI89#Emd63`?yMZy6>Z?Y%`9H`8=CfjqqdPI$Dak40b}&`UPn}E=Lh|ey`r~p#Q?5 z(G(9HyXGMx-Av6${t1v zJsj_%W8dp}L_gii>P)`uYp1Uc=O!s`)VEeGtY1Td(X>4EIMY?EQBwEof%93%c zVQ_CJlj%H>m6MawbRgH;#vJEQ?H&nKDV6USpO!P=j-1HWxA{y2g2?93D|UQam2TV<90Je-Mz8_497(BL!;S{?k@ zPLY*G*3Tl-&c(!blF8$4Q4BNu?dxNh=R9D%^;yG-MR^|M(+<35NUEYbgzh%s$S(xj z?`3Jn8ejMP{&xcfS{$&m;13gr5Y2Lf;#QYB>>X~VAFewR8%4(xLe}q;2fZ;Dcc}Ly zY@M0$(nx0517`%8)NOp4j6^24ilzRuClKZGyz|fzS*9zQk4)+90RQ%~N;wM9<)at& zvp`Ui4!>WPm^kn<;FsSukEUqV)@W1{v+sfMWXOpR120XIL7SlnFu2i0TvlXciiKp~ zDIJR5-Q6A27-pvk0|>>H=?Fv+6to|h`nipQtG*XZZHfI>Vb#+aa3T-SX=6{!&CP}8 zo-N8?zGS$Lo6cVQ?EtWi19>@|6JtBR>=Q#O3!!I|tHjv5cywd<@i!q*4n^U(mH|LULrIIG! zbblBaRzLhE9s~^2?SZ-Gn=;<62m=%}Ir#J7aZ($ae6g+g+HC)fp%VDY{zCJ#~hLLK2;WVNiv|xvMS@4n*x|S)tZiV5> z<~z1BWakhSZItZjL}B$K)iDHuP=x!&cX#1}QmF(7p`8>=ISLF%UszfA_iYCD1gVdJ z+H-N65}X4`0Ku%1%^Gj3Mg;RazI2xC(Agjaiz*dWB(DM0o&>p-ef>HtCgizHJ3W1g zDF&A3A7{oWmUMjMQNXZ@?Wu_+c5QqfX?8hw$BThXYAi*L4Gc#ayIZ0Sw~;ADWM|?M zOWOR)^5(cXjlH-^gjomRgN~L=7;XD54rM*U;RI>4A+o2gA2C|UV1xVpyj}a|9h;`d zeFLT&t8m{;b|WKokcM+c2TeBq`-h013Y~?x1o5{yjD;z#71d}<-`WzFwNsXb2IKP| W_hL-Xeg|0tu3wG^A8R@qfAhb*jea!% delta 3069 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 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00004.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00004.png index 82497e000274af8643c9f7f7857adb7ae5bdad70..30b434c51f5be56b80b57118f490c5428212d705 100644 GIT binary patch literal 10937 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 10347 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00000.png b/test/snapshots/stax/test_1to2_warning_finalize/00000.png index 9e73852e241f818f8567aa9edc051a2fd5f5de2a..952ed7638580f979c811f670fb0caa44778a001a 100644 GIT binary patch literal 13902 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 literal 13590 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00001.png b/test/snapshots/stax/test_1to2_warning_finalize/00001.png index 1c9f7d07e85c50fe94488a161ed270404313a663..98a8b6041ff7f49e3b2891ac83dd1f41eb3daaa8 100644 GIT binary patch literal 8964 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 R@OKLr)WrM>-qqFL+m38M{>%ac@Z(2|P zCXN8|7BqR=Ax%}sK35lPcNk~Y(-X{qhF$I0BkdRPWzVhcq=h%EUebt@$Wo)l+ zJeDd^@eq8;RT?ar^Ou^hH28jwgxY24e@VW$aP_|IK?Zunm5^xw5Q83tls)ckc;O754(t&;7( z{QJj$7vXGMwwI(Gu zrCq$I38br6A_L6S{Y&&;^KY^sH& zr6qjNCpz5=ZO#PS9vVQ)$qBta7SL+n%#9tN+4~FFv(={P&ww?}qz+~Eo}^~yfF`qK z8OhYrtYW*3v~+Z28lnfMx_A%`>o=JV3p*Ail$>T}sw@0e%vXwk2qviIp!&usS$ zelF_$jky)DV& zHFGnl`6`BqrO);xbzH>t>NwftwHA>b^zBJ0)>6aRVRiWy>#1K39kxT_Gcqzjs*G*3 z06|Dei^*?Y-Z#OX7tm)-wH{2Ale{HU$$(wOwBDU2n52xJrBBXuL}fl7PIvzy?1eAEjFGN9DfGbC=?2v{CC&v zXo%~PjuGc_63}5{URPJw!F!S;rS`E!9exo=VHmIq? z4poE;?>4 z7z_dNYCi?t9)ov?#)o!nVfpdmHX?2BucmTjH@9TcEuQ4T;(>RBaGCNV4Vlo0Ree4P z38__gD;Cn*d}~HS6jp~l3fM4N6K6u54h-*w;ERPGId>A*`loh$&%W#pV7IGhbpvI- ztR@(R;SUe zLZMNCPOlFb`H+%OB*rVs*&ep5i*4 zD2`lehr`N?N~7{R9*?&TaZ4r^whBIph$8;R;>t?3rBaigbOi>Je=a#wjW~JibvfvI z=;qI?(Sb5jwBxx*K4&B7=^oBkMyS5ga-?!c2=X8eu&e*tKf#Xm)!W#0#WPs*(Gfgsg2)r*h z?Kq~~ca{-zsjIQ1naX{*Pp9Z=s7Gk$i; zA;z+TA}<1^JN&!s^C7&lg$MZVm#VjlFBmFuEtjfoF&^HP8Y%mgb3BJeGHxYQsPB6o zbSt4~;M_~fVw_Ch?5uynzV}s>(~0bApp&oo-)?eyY4&>p+(W+Hwy$`i^~!T6v|H{v zv=%&szl>skn9mmoww3~^H0q7&1ihr_{34A=SWuJadxR9nfJo`6d(VKrlGNt?oS~rH zeEHmUd#wzWd1cS)3nK5Fwl#wqrVBH$BBlq*3V*%;w)3Ugt)%~~1A1hE)}0<;9)7ZJ zaJ;Vb2`4D;^Ww(%xQC?$01i7#CPW1jI5Ya4e4gAp3}(`w?M{N5B=4z-st^0Vs@U_} z8bc(p_zpriu?kVOC6@XT^IJ{F!i{?lrU`mm-7SM;Ehf*<#{r~@4Lk`_c1I!*W=&SH z0q2;!r8$onp6)ZU6~^l82O+M?n+1>}EhE zR8g++K3+fsM|SD30dDFI$RehU8x)Su-$krSiH*(M1lz%eTK$C?li=4D=oV`NT*-hq zK3;`=SxsBODdbM-z880|6r@jmC>@xD5@f$_{aJle?@&^s9l8~Rc4GU3cXm0Pt{V** zE{vF5yZoRN2eWI4p7=E~;G9Bq;F;m2!%CRx6KT{~b7fE&wR6LRyAq2(lM{8@STSbe zr}}X=Q@iwD9Y=(j+IjKiT34ukuA#z9gi1*`A?5kLN(;E9cc~aQn#iLnd%_TJBZ9EA z{>+v~?EK&%I~I4v-=fj%WTQ2VBa`h;{I%{@{pg%NuX=KFX0nU?Hm_DTRLvrOL0jAQ zWDR%eH!!DTj9vm10a$>92mP~aTmRaruAUSwftRU>FiN>?!Za7pxgnUVzX#zAX04kI zkFjIYVrBvjui~i%`&Cp_>PIURLslImIR_ebIaOB+~G+d93+9sd@e zq8b0;hFv46(AVoPWY9fd6-;eqcPA$&Lm%BTRG7aK!}s1i?)vv9^Ga;^*u%_w$95HHifn%sQnxem;I>adEM8)d9fdVyzl)tbD2s+|}7Vr+DDMQ&KDiNIT`@no!)o>g|M;AmlCp^V6zA^&b?kQq>K!gR_9fj}lzDMgo!)XRJzy&V8@FUOeC zNmCbmMe)FcXu9Qc#Kt{`BgL2GcU{a#7!G%FF}d3{8zFLw@0?wO6U0IuL@-rWRwlr2 zJC~l@4(FWUj)uG+4QUa#X{ztMico&5B9qKE*COl7b|*wgMQPsz6EC^vtgf!2n1&^f zDKYq7VjFdfL)B4p6w|pFOyr(4+hS0$0X8=9Nw9wIoFtV-Duz7zqLzv1#nzIGr*xF*Y&;`?NXW zb7_C7cOe>0wfa&QVwA2RzwFqe^K}Z48ZM@Wa}-CZ+2sd_X{|GUkuN+o?U+%gfFns<;Iy?SfoFgE z@QoD{Z`G^JDAzM)7TFi1y*}R@J4^V)p4QN6b z%t$#SwdfrtxXE)ENt-!oBz+24=$zk<0-s9zL8lHITt=EF+4yM6tRHg~=EgC?7Wap( zodUgHG^47`?ZaZR2)pM1c*BEf4#6F(5k_drnM8-=sa8ifVPdiP~yAxjk`ptz_mg;aS>&&|z$a{Ji8jVgSO|w|6DptFibfx`GT~vZ( zg$}t+hxpp^;5a+RSWzaKgq_;tEYr(7{Pd0;z+i4-M~qB{JfF5UzXkk`Y$XR?;8->g z=; zptqG{m<)#I!4p>E~{)UT<_mJC@lv#W#cf zwUx}w6w=l?DJumS`AFwl#7OU;>%s;`Duu^g_euOtd4^O~RaQ}Ix*H_8`!Gf`%R14R!a@!~ln;i-O8Lz;8puIVFh!Oaf_6_}9NSLAkE@g7yvZ%bx zx4&MgVFa*?N`tmmP;=$7l=;GuH?$kVqJ)BKjg+AY<4|q3MP3JkZ6>*gw~aefGmv$Q`CJ1uT~%xr0#~zBfb#m zE4x4Zo)m4spZQ0YXryhu9ic+0kFAj+3)R_YhCR^r@@&_gh6LDxYfD+fjUW1L*G4jZ zH%Dn-W!@Fly0j}7)IX05fjlhAZsQ+1NAlcJlU~>nI-%VFx6TpVz85y0i2JhRyN3>0 z=&y0?x*Uq1&z4__>uaEp(o-|bfBH&?GQlD~-^5|S7^zLy9S(@;T6r*?zlBjI zzSNpUm&Um8xKvh@4+{&yjRPTr;c-^oQESxqfKyrBR4Nr%d2smE>FmDm=@)rL8UU+r zY?n5GosJ~*aX$_NrU(AlpM`(u<@FA3uL2f+XogHJ1xA*I;?ilX!!P>&nIs)ZT-Mh! zQ+q?Fxv(o^<-pp8VZ=?F{FBofH^D{*KXMXxQx(9$!wJ=xU_*uI?d-DAmw+ztxq60N zx8pDE?c=kdcwf+jI)z+BBwTkGjQ?C1iX&7|0_x$(yq+pW{EbBovOaR}oGyE^dy`#o z6-^E_T>tRo-iJKOqH3nb=lJT$ht=4D8b}IrqwvAQ`^k%5Coa#&dG> zjoLMOY@4%mXmV1Tl54i%ylPzBr_;2^9C`UHI_;$~rbp#Gc^NUNCiQ>Ae9|#ji8MRo zHf+hG|Myw{_T96`bmUS!+;)A7+WGCk9-ym+X%buc|E0M8Z+Y1eecZ(b2$wuY?icgF zg|Vz~)vY`i7aCwGg`7G7(g7q_M}73vRZ&(3Ql{JbaR~_)gp~NxDigiZl@H#Jvo|(2 z-oVIp`IJQ)r~H3K_O;DN#`(<)0F=UD0LWI9v2yrYEGHh7QA+9Xd%km`Cd}UwjjW*r zHwreFLeJ+NzB(Clo?-Zb+Xi56c_EdtS+{>DBw3~dl@P92^oY|m9S)Yo0`VEpVJ%6( zWdKUJcDI~O?KoT4-KOQC?8?G{X5RIoYh~1YpK&&~|CePzN@GVfN789X`ij~HDX$Jl*q!0AGnE*+g&ucUqs2OLEl|-M(pDMU^3J3r*7=~8^4=hG6 zbD*YlcFZ03VQu2gs1t#(@Ow)<;OQgpv`5^cbuGUM^G z2*292Vi)>H$!Yo6wASGKtT;|guFViZU$3Kom>fB&;hjym%mR zHDV=BD)2CPZ}eVQv1$cUZ-Ll85ZEvp0&pUbMx9wuE3(x(WWYp>hA=x;L`BRfsjv3FN>Gg&Anz2fPa!Uy7cWPe z+;Kmj6N0Se`QV%?2x^{lTDL@o_jvWdLxh?tWpt(C)`Rjr4ss%y4o?LveutuIS~~5v zey(E~KZEN2cjMLgQ6;nqWl=G9Y}Fm?%bz11mbu` zR~)}{jX~sSE8)z6SkOQz&6e@t_>X9@E@DEU_!IXKSY1IT8BpmQtHyjyK+~r^+9&}$ z3s=T_)5qw{s8}14pCUgJan;SG(Nh;ip69BRWoH5U1;AP$9;Jr?1q4FW6f!(ksqx1& zAFE<&@3@!3Mp)6RHPyV5^;zjk?{(f?aZw@ADa3*8JCg&Mrbob{kzV^mboUZ4Wz(Ao z&7dXb^z;cfB>gSmrVX8;%fndcglS4I_GM%EMM+jvxn8!|LLu$C>JpI04E)v|v@RAW zE>$jlSf@qNKhC{b7Wx4;hZ8mcWD24Jp-^Z5IiyRD#En;tumGLljopYZ0bC^D7GJoF zaET?e!%oXa+rj*wq=qA|qy8v3@MH9e>>`cpLJf{jy4L%h=D2P^hb)obS~@!&@i94- znU|l}yP#lE0Ii4<@ce2oPswS1{E_ApwC7)W9J%luUVYwL+&91j71`mL?Y3oYJB^T z3dkJI+cPvs9Cy<)E(ki94DBI(naWLb-^Xck1`IB49EfCb@?xm6Yge<%P9ew;O>wJm z5#b4mNkqL9?}YW14d34|=vN$51U;4Tcqqv4>UujrTTu$g3FE;0j_s$LQ$H3hZ!fA8 z#>q{lE$#y}jOjbo8s>u*j`TUDtU_MjSEk9WW~ZcdHM72lmW!mxNBCX$R)@aBySNRl zK#rqiZIyhgF(yQGvWtD)fWCXU8!8QQLO*v#KY6yY0O5K5;8Pf%=L1{KWGpmtr6-O} zFh2Yox7>c^RhP3Ys!qo&>^?)2j-*;DFwXy#Z)X=Oy4qD${8g~&q&pL4iO$2t91Pm$ zze@VP{tZ~nljF8aVBVZsMzd*5dr1R3#>2(M>4-d0BS)odM6WXOpUx4;lY>0fKIWv? zYg+|EjTPUQU4&r~>zQ^1m(=qiBY6i#7q_iqSZ=0a0S~?Nbf?`Av9X`!-`W-rG@>&P zSUqhO1e?71Qm2^FC6MVy1K$9N8gkwqrGQP?_51c8oi#15lJAqc8~)pE$`&$qvR>0U U3X%uB{+GC7lW>g@OMV+P78-3F$Rj{dMtr^y?+c(yOBO(WV=7CXvFw z_T}tb_~%!5r^H3G{(ZVTB`^N@VxRJ31fu%Zq9^WQ(Uq58CL~^Psd*bHv@%H;A)nS& z4>~BczP2?vs3s)zZZ}BCf1iuc*FWlnaxVJpIQOVs*he&eSG$Dp-iOC_$_VNFH+~>x z8-y1|Zfjc2zFirn=9z(?s|J3L{}tlD%$0q^b|0hkq7X$lXP4gp;6?o> zf3ct9ybQU-sTaytuE-!%Tf{}7tzDWD)kCz17LN?&AaYY>B}qN-BGj`i2<106s3yF5 z(CfQ$HGQ1lC4G&=3B_c(DL({9-|*41%~XD-D;js(e@Aqg^DgADQ9Vd4Ny#c>h&F8G zN^W9I_Iguw@o~Ryqe{`iCT3w5@ruxG^!8v=h!0IGc$bew?IJPbtfMP3CcnV0jCufZ^uSg?LJ+-8pjczeILF7mbnZ^rnRqa{Q2qa9xy|ZT- zTzG}}qT{N6RklXzMKG(cuTR-()p)zY6WR`5$!O28wnmj^$hso+Z0{T9eX0MIhiDj6 zwo*Dsf-YSxM$ zscax{Jk)uMct&|gT34~x6;D#=!Fo_trS+ogDpL$8>{FS|zF{@d9Gwv-!BJANDw19Y z^(enxH6}r2DqLs=mpm_{!eF6jll8A0Bh5!Mgm_z_Wl@$GlKlW)oH;Xz_hbg4V4OdA z%)r@8Zcp)&TF*Ww8g;@Gow_&nxwQX1Ck?Vvq0HxP+P;Vp17C_{iz4ZLsC)N>WWaHX z$l>5ctXD0GYB^|Q5;o87pBU7I#%}9qNVWg%kG|1j;Z2^hJ(pb=SpZ6ZFO0}|73?y& zK$kzKLK^nJa~PX`jgrRxgMSW{`tZd4(YlG|x1nw-RvGgx%AY;5K*!7`#+7!roAN>TJ*I-Sh85a9*_(p(jPBg)xfHGwv;ikP!$( zX^`8YPMury9Vw`q1Ql+r^6l2ZY`Jhf(n(j};qu{zMJ%%Ltu}kYU6STBbgKepG+r8h zYsGI@{%g61b>3amD*?lMm9$`;km7 z>%W;^2ce!gaGjs46LPly+9DC&7#uMGlNX+ZQNnL@uS9R6`Va(ZO^u%Vk=szb*Ytb~ zB{VUk1`DY0-9cw51I41qzVFY(E2Ne#2KD3?E5= z=&l6rxq~5Bcn>H&nvOPxc`MiT)1TDx7X4GvgWek1X=!OJp79|o+o1;!9xRZw16+~w zF{o18p#`vhk6Iq?i5FeJR3kf?&ke=cWPGg3dMx0vy7X?W8fzvg^|7#MKPRh<*LG#S z{yIVVeSI+)a)^HJ=Up|VV1WgB&FZ*6%GbB}YDl=*Qa2CP ztEP%S?<%${Z+~^g-sw>1QY2l&2IGf?#t&qzRQeR_LCPx6a@A`i=SI@7RRXL5-JWGk za?D`-9g4}#|DFq+>HBleA-*^1nBwkg ztDYwgJv&E9q--=5E|vlTS?(;Y#ed2EXwo83Q^u09FW%Lvj6inlkFV8 z7NLxR$f;+hrlzxs<_;2)hRM1?E$2eI+XtN+Csz8KLN?cb&9@A&(vydvnagaA2&G%I z(EE&8nJLFGJ@5-9e^+1uWkcP&{GyG&oCcQgk{Pa9Xyn1UXVg=pvm=o>H9buffJ>VR zp&V+<)U!(J;(o7j7=E-$_x4piOR#9cgv;-%jz}Gs*K@lXU>q8^y|pChtkS;j$Vtdq zhg4RMFGU`(%Iz%;LRD72WjK*Iz|~P}si^C{uC=6kR&r5vz1?4&Mehb*pVa*JQ+ZRw z4t3z8O8i*wBe$7pJuKd@vpI>xi)pYUUDE?24IPx*XtUezQP)U~?){muOPR>zf*akc zg;M*YnioZ;UqMipT#=MeOxN?*$5`x;`=c{!bA@k=71I1%v3lY=orZM(xqMpb_qiOi zGze;0KZcY5Q5O2U9vMAWZM5z{ljyehNC$IEUtMn;IGE_H>7UX8pF93yo+m(z5qRRR@_O5L~nF2xU1KtC)xl?Cg=%xvp>6B>a7;g_A$i$NkuQxlq}EX z*_|?w5Wbb(n#lv&UQHnfW`Mk`{xk_e&42g z3EPKr9@%WSFBvg>bqqgxOzIyETPSu&}r_SB}w&K8rq z55ycP>`&Kv&sD%>-=!KPf+rmf5<^7>qvj=RQmBc=WyoV9!Gqx|nV@|xB)VgnV_5tU ztGoWr>4pf;YIv!<=c`0D*QsL9`EUIP|M)h4pJ`!Y8gQzWXShJLmytB~^1rG#k069S zinvb|yo=Iwz;6WL&(%dZ;3k92PVSw}D>U#huMTvMHf5@ZVb!Kbnini?gOPf4c^r#0~$Ey&J!) zcMyK~jCNhQm!JnJUJdF|$~JgyY)1eSN}%eqMSjU8;@P3;Jb ze-AU)JEi*jqG_tEi?)~l;(-zlsm8_6RR(du-`9uMUD}rVr^UG#HK26=*vNxh0}wA> z?6m2*`S!?Ns=qsP!=L%{Qw6lcBd>GXi(s5IzKRG+!ka;+m?BwRC zr8cT-`}K6C*xcqhlU6$am-~f=LoPyF_agjB%PyE2cWK6^lfs}Z&cXIb%jpOO9*KJprw`?VVF1L7*!k= zCi?K`WXTXd2!%!8!nO--Hq2GuFnJR~ri7Nk+W-LEQ_n|63b|<4jW+=(c2yygHV+IK zgrbBxBUR*CLdG_tqoJ5!vVKoJ(0sO{H>ytWu`m_tm!T6gwDtv|7T;TEd~6hxP9*+W zCHf=R4OFL*ZIhu)eJXY$^+V1HPob?d$-9sq`+iA+NCg}QRCpP$Zd_dmuFFtPr>bf1 zeb{u@N3xNxT)7Y-_C{UC<$wh~UL{VsMkrclFQ}!s4qRtfc1?T2ZRc_yF!qdH&@rRR z?Qil=g%Uspci&f5_WBR$_5ua%B;{cKt6gvUGU8Q=EoQy`tZ-DBu-WbNy>@zKU7j%> zjIszFD!jSN=W~aB@ZE)*V&@id#?pI*EcXA~sG=52heCm4VX?%h%a5I#={yoI+UB*c z88@_$afI9iE%;({n@Hbhy24_s_HiI@v1mGWv_U;d=?YdDhqm#0rnD_}WW1s(UAcQU zTwIfqInT?q>{WaI#fpF54#0ZB5WWD?+6?M(sv61%pq_m1B1|%a%fIE_ zN(nV9c>e7+j`GQVvlUo)`7-9KO3F>B@G5C$d3JxJv>DmYGrfJ=h4^!>yK{`d`S@dFPX*lIY}#)>_FW4NpxQyQJb>0Nh^K zw#Kd7N)kzW;_y@F719g~{eyh*FVTX8+ym(_>9+%6&|LJkTjmuEA*pCtf4gePf=;R0 z_+eVm7hm!=XdGABP;K#@_aM?cuFYiqu!FuT^xA@I1FOkt3MXQ-Kn!bi>unZpxL;-H z+_aV-Zb=wXSK7YrLsKZf5Z~feYY4&~1gawVB3Dd)X&x1kq7d>LF=MW-;`CM%aACA-wlLL8QN!3WLC94c_t8mSs^*iX6k zP6{MoN!KJe|CO-TF1;JXw2TsanCt)E>!4Ku$WJYy(i2~0NV*-ZB=?BRH+hg(3AZTF zs+-V7OO{Jxp1E&6Rk6h4Qn~23rAQ+%$kwj49*re#u~-dJ`DH^^=!i?PoJbr^_R5g% zMiDdz_fhRu7c6^LBiq+C5>hZ5*y>fw_+CXH$B9EajS!#sUx>JlmyDRh47YP zXkKZB?i81gC(k#e-RrIYDo@PrnFaRcBy2%;tSWIFAb(i36uk2}iZ3JjOw!M2V`?Y{ z09ujGL%QKw5oa;+@fRYp4^e(b_(*0=8K}DuWh*tC1tT@S*!#Cor5kEqe64=}%Rgnw zS|e)N*7!0H%wcL7Hi1)OcLiUjhnEE)g0m#TMbakndYB-Jofv(YdE?k=IZZdo!npJc zx2`a|8NM6WVm^i=|aov-lGA!aQjJbCS%8kVBI{OKqXT1SVHjqwns?AUa z_VwUOMck#XST$qF=q_Z+&lL#tk$D3MPM6$gbH1RDa`r7cw$J^;uhE+@F)ut!@3%ZN znuP&4Z>;Q8H+#cg*7)?T7D`;AQ@i|mtlx|BB7|X{mx=7=6A?>GNx`x!(uxO^0!l2{ zu>U>Sd*(p(@$GnhR3Ld&pdUYYvO!*+bVOnKRcVmJp{uP@iI1W#_Sf8w)}2k$&kZ z>*6DH0F~w=hiL4XPziVKx`ee~w;MBbtUO8E0%lxt(Tf3bEtUjZ^N{(}Sx^XBR7%?U zq3}qRmv+DFqV>uWZz)o39;{i%URcYP`J4IU)$N{J0UYAg5BVxO2OD*L#>V*;hTJmV zzY?9&8V4_bT^1xu&72wvaC9{DjK&(n%j^w8Y+lPtC1xW>RB|7ijr^*t^k9{RkbxQT zcsx3(7MO4x0+B$sjE~Gjqjr7yjh}@&hl4e;dtmr20iRpzO_)*W2HOGYZqy z*IRx8N*2IB%_W3BF$gcF8#xyT$qLjGaV+m~P}VnOyR8A%BuCkbPng(>;h6Z^h$11k zq9yUboGGDr?~)){@mhfRl9moRx5(FcHHN5(kC-^yFNKG9FDyR1cAq77zw-^b>r^XZ z>_XL-0gMK{tpS+8_4i)yWkct*FfSqY8kF-IO1Y)tkKZ5^(%-|4H@f6V2F*XQN)GUE4}X67GS z)e!+YP|HqnwmqOdIF77Dzg!LGjH@M4riRb;AOJAZ@M)s;b23ubmbD|469K)0NKPTHimF_8dra1Z^(R6q6B*@uB&v^K ziO`7ZR3kmf-jKlROt4hXif9KL0X`>X7DcB^qBFMnmau48tJ9%tjf-h4L`A9`U_ zI35sHpl&g^ACWjKnxdf(%(8;kzDRL}l@BlAk7!BzAC;^w{7Yd^b!}T=3bj&Hm`;xq zyCEv7xOfo3C6T5E<;^QhIl?wu-{I@KEWTTaA~l@NrfmpYTrF{Y@PRgB3|lm>#mUT> zdWxb`ogBy<V&mM0>#WDv>R@4-uxKK#fQFV7xEaO*pkt#Z0x!Mf#7(CcA-~mDR<=GpzNgq~ zL~Sah2iQ8C2(^B9YvK6W-UjzwyTwLH?ORc4AK6>yuU}j~3j+W)VWCYwj1wW9Eb(dijxOgi64!Qe0k&tXdhtqgFs^9+R_yp z*MKWupBY0a3JsTi0Pf-y+Dym7O|g5c>p}3am;1Fkb+_!^wg2raLWzS%IWSk=B;Vpn zn990%-*X-k2~x44nUoLe;=O9k;%7}7(OewG&lY&5PrGhiGKDcMT7o*}-{z1Ujay~C zWBYDO(DO+|8)-09M2?D!i%>tYOi3&&SgeUx$)+l0mru(6_gcamDEAT<_=wg%Hj!~*H1CN+?JQtK5+)NxIWsW|4cnaE@>8-o@wo*|E}Z*GDhMn& zJ3ZXKv9XcS|106v%-D-`-L5(s@wKn)&KP^5-2FTF=%2&4`O?pjtkc z9ANVID(At!UmN63sKi)1%pCAu`Cf`eYi1|I-(Gh`uGoVrx2?C@kkG|HwgMEaRW!9S zV{`q+M3@#2F3hBDeSMwT?5P#Rf@;AX&SbdPYIPI5`#9}$mXJQy4KtidX>_(9FMoASACTy|4CIJ+rvCvA99~+LVb^rsCzX2Y z(D^?s337<}H`5_-=H76uh2rdbk#phG_A~^fpyW{JsoDiduhu@7w2-YRDbW7!LHDyT zm{$a=@<|jqwrPU}&UHo6=4|-AxXC;EgMYHy;OCD|=&o+UyJxXz z>BL9F+nT?-nu2;Ywdz?(lVWJy9ep`2HYn!AU8G+KdGQEto5!*w++~MMP+3$o+!ob&d4?oeKK(Cx_QStx}c+=WKFA!XRKs7m%!*w2oC^qs1b#wFmlo)bCY>& zFpmXq87gi4(8<50X+jLusXV<0!(J{TNLQ$SCRnQZnTE0c5tlXu&|0-HrmlNtU5NYG zS?41oDy3Y{eC>C*=c;<80~<}P<%=PjyVIA#nX2iZI{K}#lOynVB_|Jujj02Wl_1>b z$+(>H7NcYCC9BN0wx5`d#IgC8tg=RXuMB<96HnN<$3Eic+`PT0R;WETb+_3=BZQ3f z8>^YSyfNVC&h~>~pi{|FXsu?qnlJSd7|DXMO>|QT@KC;9vqoG_`zX@YaoW?L4Y};E z9u}tOoOvZ6#u+mtfZ^AW`W4(Yr$s4>spNqsE)* z-34F#v6`Bn=5ZptEa^h99n}>NFc0hqw7A>dL=gIcyj0qEnR=jXYk}HmXYX^Wc|2bC zgoxVq<{Z59&cZA?z6vURd@p5I>fVi+#?tw-VPQ>|eV$AncmOFlS$mhDQ3p6{&G@m{ zn0g3Sxa67`671UiAR@CoTkQ=x_cCd^bm>X_$QooYes)P$-bH$IA#E3O3wek+&<^tl zj@#Z=3FBkyBMK0ie2MDXS6|4vy<;>4-iuT9b+%fm^=eVysnu{EodYmezxhS`>^-2^ zA6DM&0tA5)iv2c%uiV!#jty=n^EOV_J_X1h#=XNC<;jc0|Jo2jtY1G?UfR;0VO|#G zhMYwZCYfAp$LjarN67E;BcsJ{aj9)HV@u`pB5HL!Y)-erLTDcUz0rJP+LO;emF*Nj!-n$5)V1PEdTulQ zexB+f^VRpcFrLbzE)=|++f)6J5z{A6HJkQ?s$bnUxuT2L6fONND#))Do3&HWET_xN zq>5R4Mg8I@h`>4ft%a5N*~q;7Zk>2NEDts*l_%}-Y;_M=2RF;RAsJeq2#k+6s*9MB zhTdHaqAI#zcj&R@=pya>OU`eAZdf(Pmg-mtrEp-99uBg2_YPZ{yqh#;4<}43;!4Y5 z1=J6oqKS6h1g|}~)A+cHR<0sCZEqe7{d{dEbfBl#ur)(RcMr3Bbq&Ep1V3+s7!Fqn zk_H?z8HSPD3fPwGVdg`+u(^2_Z+hBntH$zxQP=c6ycbR`m}5zmpVrn_vb`2{5IUp_ zAYn9}3L5Ph3`v~{BV?pt&mWgc*F1I`^(n*#VATq(f_I`A)<7K;JCyQw!-=H2&8+~vM)$uN@ap!(&(l?TQOvuAv? zCn9hZDwA6e;;>;ll+PAtd?_Y%lT3>Egj^%2YD(%M7QIa_BpguSXx!(s=F@Vg`Y#k# zcyWtsNx|S~4sWqtO@A`P6Vq-?aQ{c6pM4vIDy%hir6TLUCtoL?N)6Ml*DpPME<#(g zr#?#P9r^=}*iJdI?|hb{qe^DCr!{OKGiiA0?rvQaHj(a;%041k(60B`%JXxLa$bnl zh{``@rLFsNbE-FO0?YWbU{akb8;Wr!od@J5N^WXKSr7RtRo(@bn;3bK+_YB|DV1K) z7rpzCwdEvuNN{rX>hkl z#xT+ske>p+kpGt14Weib%O73h@IeP$V9Pe#KO~HetekHQ>W-Am0R9896i0@BKWsjr zuDC&`o(m@)-ZF#hn|2nMp(KU_zFq7S8A`5uY zOAd!t9~@;esgwiQ{;uOec$)r3gio*BlcNV+DCR&D!aJPN*4N%T#ww2Ie4WGHRDDF5 zFl{1-L}dm{sB3k)JL7SF)9+TBsyp+~8xCimfd{O#ZzM%eaQZ7C#<#ULqxl1NnW3}+ z6^K6$R#q_Fxas1v3weN53^%)xd4}`m{}g(kT?%iGpFgfZR!{GA@2la{L}o)=lT(R6 zu7EOs{EH2wt@{s9%=ZgnH{5ERxcu0KE_9`}X=6varF4R&c=!F?uz8O|od^P{&s7FZ z(62|masJioN$J~M05nh>y%(-TiF#2=0}K?zQ(fCx>(BidFBqtK74Qu(TtPfAeQ)hG z*ayA!Elu~VBke7@L8_@I9?W^dL;Eh_!Uv-WEdhuK@YAUf`@GnPa$QC=jQg6)IR`3I z8YJ}8m!@(EFdP1xV@&_aiJ$)|X|4ZV=D(!T{&&m$mnR4}189fW9RT}_+*F*I<@c(T zCO0}?;7H<3-My6IOPJKeYvde^*DJ%Kb4!oqfozBBL6dcmd@LGp#Oi+uk`Z~-RIG=DgColaIUt@Z2Buj)00}80D zOb~~-&*lE=qHWnw1)8pG1=vo12D8(whXB{Dgd_|M*7l?+1W@?ilg68%6ff<2+V3{@ z4LN0Xk2eALf9ItyzA#Xmn5|S}z$*`N=Y=uz#qYe#?;akDB*<;yo=!v>KWcaTK6SU8 z?iMu?00?wh8f@Dkfba#a10gztbARQ}7dwgvfm>W-5r{~__ok&#%urVx($CM;!v7|h z9)v^%-Wsj5lV5dcBq6r)$|t2XV(#t-=8z@@27{p0Y8y!ngSCw0GFc&6RgC zN)Kg6Z=y=?nRsC303Oj}MW*vItS>q`q9IC_@F88wGrfxXmMvOnDnKNy0vFNrA#Zbs z$K>-@nagb&LD2KZJxu%tuf7!rz#IOUm&Os=>Eo1gui}P0YyB@(Xa%Xnp4lRd{Qbg& z#vD-38b8+2k!o(%T})l^Fn3rO&D1r?AmC4>r57F@bQ+9{QrBylkXgsReaPhiF_5;C z2K@G`tr8jA*tW97-t+Eb<)I$d@VXFk&+O{g%A(|Uw~Y5EVWx{F2<*sd(pJ*1Ys`#C zl^89Rtmn(GMZ70NF?@j+1ciM`rAwm;#&wVztZ({t4y%@KPa2A?np?5xlKh`+JN;oG z)pc1`FHJIkw+ATGG$GBG7ZKq*mTAMw_suK0LFK1+rfvXIkP1|DzxClCQ;UPd1Z-8w zMyZ%%w5oijwC1c4d^?S!d9qFh2rs_1P2Zl?aC?GF^(qWPQ9lJm&p51tgT3%CnboJ0 z%tPOAfcLv3r@vnn-LXqzCP_VN-$n@GL=_omkClN!FnlTG;^U%*r54ekL4)wXr| zX>E0kdkPB`OHxO|kI)npN>5vn5H4aE`H* z>SU%DRX5VIdsOzhP|LK1)t=!j1InMDye01^^mYqAllp?8UBZQeQ6A5?Pi1REi}RHm zvR3?7v#B3SV85!ifX5GTc8goRxSMaRnsY{OH+t35eGlKlLm5Csl!nBTp%9c73e;hPp-m=|8%1Q|<(!N>3+UIFo&Yq5YTF;MqRb zdRONijC<4-8VZ#%|5Ema`@v(<$L?=N5j1M9o1EU}m0YHj2VCkZQYg?H9yu+SHQz!# zeax$CTFGmQv=Tid+f@(j^^ymH!m&n-TlT@r{^y4S*z)lZXrhT>i#(!C)`%_$ovO%7mO|7U<3LkKve`mC1h0Z-!J@N01Q~rPC)Ps-N4gocr z?dDV86vCU5VHcD*|KQ&yuSFO_xARMb^5_=<=CmMv4qGc zM)57)`V$n+yo*D*8+0pc_Nb?KkGr$iS9D-ht0u)-(kt0T;`-zhOX_9 zu5B0*h#oYBC8qa< zHuZ2g6h8)O75j0bP84t`c zq0y5yB>yuLQE}3sr+#`R8t(-J0&=e+`T_eLQa~|i1p(X&nt1~xkn8Yru;wH!~rTe}5b;Hvj{MskYSfpT-Piz^pZe+mli|R`z z4xPVtu$AgWC3lT-V9==|Q`y^^&Agcyi0-V&Bxm%Cz_VZ^pvC(9%iK^&AmJ?HzD*hF z^ms$(O@v~oyeMaX90jK4>X@bWUK%8LC6HO4Y8}H?>B5Rtmv*p=hGIR2bO{K-qTo_N z5#{@FLD%opdmpP6O>Zx+T4!PlFL*Wl>8$oif8k}Cl)gUuu$xD~X4!|P32I#z z2BXq7`g3)XFO+3W9KJ$o^r(a*E&wJk5R3f1-B^4s6G*V7y}9`dpGZ442;~5}4Oxw7X;(Jn-*BcU z9N12K9A*Z+-%sB3xAEzH+Ae!4yL@(%q2JDdEqUtQf8I5Hg@2PBcuat<^3}7|X;fd^ z12macrQhg{MSwsc`PBj4%j3Td0~=40M%G(xl_QSR*;_>d867h7{%zil-PJ*FE0p{q z8pakFS7~>wGyWRa%=DMr_KbQw3|+E~0Tgv>JGTuTkLNql3{x}iRUr5nq>WoauGqv4 zAohM8t&xk@JE@?l^NP+jIWC25VkY6(9)XIAiUkD)xxM~@`74vqr7L096&o$GUF7C_ zQyX;;wvK^vd*@gz7H~*m6D^^SdM5vwl)kPz2@1TM!L{C{&{dakBL1EW!(-7xZa2o6 z;!?@tRg1ZF`{ExRRU+^YgY!STU&&B*bbJyvCXb2^{QLx?#{LZQBrQmR7QS`a{@VKa zcY7*v(2PjYJV0Q(u8}>a>u#Q>%R(j3~5aYlH}g0vxS@o zj0R1N@13uMB_{NoB(@54Xm^1ics%kt^E-NZFkmd~erm+2It7c&<^9-O=4o%z5kDCt z#L7w_Ocedrelv-X#elBjk>Co)wR)?!_o>* z$Kk#+dc6!Wjt=pXfWzWQE^>Wn%X zxY{tF`~YmypH8=ISKc{_qfHqwkDuGMDFpoO=c;N_Z+z!SP7SWo&M2CNUY3M(f erlo9)?7uZm5jZ>yM% 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 UOuHCxO9*6aaQk|NzEjly0h~m@M*si- literal 8504 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00004.png b/test/snapshots/stax/test_1to2_warning_finalize/00004.png index 872040d7208617a5348a017a1136dac548e60c5b..0e99f65a248bfd398b15d70a22ed1c966ba8c285 100644 GIT binary patch literal 8962 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 E0Lb}KfdBvi diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00005.png b/test/snapshots/stax/test_1to2_warning_finalize/00005.png index 1457ea6de14e83f066c2618b02c523630a245228..f1bdf1d45e8fc500b40b78ccc96032918c5ec6b7 100644 GIT binary patch literal 13357 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 literal 13331 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00006.png b/test/snapshots/stax/test_1to2_warning_finalize/00006.png index c3204381cb9e2843d685378af44e2e20407e6def..dd3d22931f53e0785656c26a387ffc726825464a 100644 GIT binary patch literal 9292 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 UOuHCxO9*6aaQk|NzEjly0h~m@M*si- literal 8504 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00007.png b/test/snapshots/stax/test_1to2_warning_finalize/00007.png index d796da79ee24c2a623319fcc2bbe9f8fca3cc134..fc557d66f45153e0d648c7ff02272eeecb92a539 100644 GIT binary patch literal 8843 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 literal 8101 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 PuIB3GajyDIVEVrSgEMzX diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00008.png b/test/snapshots/stax/test_1to2_warning_finalize/00008.png index 92c389707b89bdd89d7235c1dd76a8e9147d5f50..ec79da9b38b3dad476d5b42d8d7b40d938149b03 100644 GIT binary patch literal 7805 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 ID)g8C0X{)O-T(jq diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00009.png b/test/snapshots/stax/test_1to2_warning_finalize/00009.png index ee463b619fd13d09cf916b998de1d5f07b74bffa..abb4b7834dd1dcd0d3d1089d562d4519837db08e 100644 GIT binary patch literal 9483 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00010.png b/test/snapshots/stax/test_1to2_warning_finalize/00010.png index 7a05bf7b31c3fca94a4a464ad8709d1c20600e36..cd2f52759f160c3e2cf6822395ea675b8c84a851 100644 GIT binary patch delta 3463 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 W_hL-Xeg|0tu3wG^A8R@qfAhb*jea!% delta 3069 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 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00000.png b/test/snapshots/stax/test_2to2_finalize_1/00000.png index f3c2cd88fd4d08fe8c4882caecee2d801038c85e..81651ed8aa4b9bea59d1226e0f71ac491f739b56 100644 GIT binary patch literal 8957 zcmeHtc~p{XySJH{rIl_?&9TAEojB!~nrtgGD>b({r8uVMfMOzQ4rHd~SlbG7K+W7z zIAel2p`x-2$JmOBIF^)%Ln;mkoTv9a>zu#ev%d4K^{ww^t$V?Gc%J*dxbExvUDxk- zlXlb2`p`jzgF-?=hitB1{#{6D&odz*;Sw=n;EJhzONEfo$u67AmbYRG*$j3bwxu)G zXC%)2knZU_FWXx*<ag`;CB&8e|dsrT10S4;?ILoJ!=Z56(V>0Xw6+D=H$(CnpjIaG_0^${s|MTdGz=i9|2+7j52Rs^L%DFVYarXsStm zWUQV9i4hj<7og=X8=ltQ`2a-8CeL-3d|caQu|k?|$ft67iL1x&)A5;s9W!T7Tw!c} z_JPpQPKLHrJiG9`B%RHf-M8oGg5|x1rH1njXnFjD^mZ zIq7mg&m1>f4Za_f7;s4fFrxDT7HeT)@x#0r`A69NpCmoG$IJsD5fRy)dE?5RfXO@) z4GB_O#dF>X-Q9~ne^5X@U>3@-_XFIdM_ymA^fqnd^R*dUN!P6!I`tFo!l#Vr6^Uz9 z_@bt;IB@@|fwktcm;R4ua;~nlus^R-YIav%O zVkzm-5~3qP0#URl17hU-v_PT^OYakJvB6DN&(%I^_R_!nQRXcn-T@DU5$HVF?V+4b zd0`eIBtM`u_ND(=mw)sAV~QSL2-cCw14$cn+p^*H8~yw9ULC*Yoz%X=R$nsZZ@)jN z&c&G5?hzRYHy$ah+f)<4{L@Qc$+w@Z{mq+)@LL-~S}0?&`FEFARg^_;gtT84XPv2t zSncx$Pfd`-PuA)#lCLyolmb@WKYK}ue53Q?Z{8;)NFBAVFxEY)fxlaSv6a8-AMtgg zj#sEF`C=dmcbIXpp1LiynOLA{>zMCSD-Rd2dqiouDg9Z?8w=NS9?c+3e%d3opHifJ ze=e>y-X>@8*rTUEZ7$dO65F;Vb;}LK*fJ`|OdNeAXARgHp=5t&ghr#`_CFT2d{+J) z*Nfv_yZ`XpsanY!UFiw1Z(4a#Y~BTqgVBW16H5`Iro*wk4ZDWb>;&)VVxG#RP7U@L#MltN{1hJ+ZJH4^Ab^gAK-WCzAcZ0fqmVj zt;Tp1x=j_2zGDUyS>{GVA;ar&d2`={e_ z&7Qw$RIlAOtD9bWKAGk3R_&}gX|v}s5VfQk7-hJrFCcOiUz8^&66opKrDN&stoKgN0 zHER?pSD`zDr$vq@w+sJ2HahL^((zDwAWirOKNhjC_A(uBOU+CO$vi+>Im6P2){lLO zRS~g7`2#>PHk?!o=JG6TasplU(tb_%ZS}OzwaHPV;55<`%dh#3<9Sa?*im_$*I(6%iNUTom_d#Gm9&y2*>Qu6B>vR+0EU(NZFJ$#i4 zFBP_wRC-G8Cjdq##F?UdIKny^+A})Ccs7%X2?>M0@Za9p7|vVx?)zs@ew~|lb*v%E zlHfw>_Hsi>AC(79D|q?He{T8xvUjU~bRx&Tzotfq$by@z3^3Qe!|z!-(l%(cT;h`{ zYeflh0V&Vrp6o4B!|QQ88y;oWun_$SQW){t<|yQ%RbtWurt+z8=-|D5GNLUj5n!MMFh1lil%(xie?J`+9HhdwBd?rpSl7g$|#R@bH_z zrk@lP9T=yNuLSoq z46;-ox}nB`SXK^O5M5)KMP$r3RPa{8Th_QyqF`%BCt^@q)9F?YU65-{cYQvxdO4F} zgz65QXAN(rs11Mz_D=HgtJL>YO?Z-_(H{xp4};Zge8W-iA=haSevm1PfA3%ZHx`xS{U9`^YE8 z(GH4+h#iF=n0f~OG>KF}P2E~0moddjgAIT^sWn9?wA|$5LzYd+g1&^40I~BqjxVFhea>B220>N2~>RomeuCR`tMpn<%L@rV z)7GkhmUUzjd54c{fns<291PZ0&sFzMS0Ux%U_352K9PHOM=oe*^&H_Ai6|PppJulE zuIdI1x%YkTWFDoVJZNX`ax-HIW+HL;A|~j*MKLB&2(E6R71lEGdlp}k+pw=BC9r7@ z9De>iZAf(a%C6IJyQbf)hUZsbLB_4UHJREcgpP^G{;Olsk&Z{Z9Gg8P=^AqhXcp&w zzWf$9WF@=z?yiLWH=?yHY(rOsh~#@Uz2YR;Y|7!rPwNhcNV*c2HcwvsynvQ;ed^@& zGQlrPFSWfXH^VxLI7RP2PTuYNIdOziwC6(dW_yX5(6RTmD%~8nU0PQ&A#Z0{sS1k? z%0D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 bU~dAk>~8X@C~M$vEkZU{c9*L!dO!RRxgBn~ literal 8201 zcmeHsX*iqd-?nOJx@ehpS~`j@rn(?nyV$zXQe{-_yA}1nN~{)HLWFM ziC7bfELv67h?F4Jh_$3dC@B#M-n(-g@9}%On+cm00n?>x`z z&)=Lc@7blkOF=qr{CKYU;pHF z?%;nO{wE0kJ2K&|t)x~Vapl{$_|K060|UAIu_3#!+`iXqJk655mvwrNzYqh@97Yy} zJN2}58^Iyj>)TX|dnQ9YE<@|H+a^-A&NSv2WHau!O>Dl?(<*A4u)U>j#HyVEEh zVPwn9t=m-ZgkQ!?tB`c+R&DcLK$~gw7hZDgPQ49*&-t%6C%xqv->1=x)mJ}1{72h_ z4v4MyP>)z({@!Bz*tHg=v}Ka4ix)X|K`|Tl$7!w1vo(xQB$h6uq|dK4G6%6Q5?gI+h+e{HSfB{ zu7_pJg=ZEOPr_mhbBdelTJGI^{iSSoEKb>Sr(P{5G}l|MkY_*zTWJxvLP~A+%ahE8 z(S-$Q&Q!lJq1D}8H2f)<_S_jaBN&fI(G(0ynU@nisalG*! z_(UweN0f*_Qtqb`1OmaZdIT_`)D1c0+H&`vyyfI#^(fv_(&l1Zs59PvWT_|YrtscH zAz$to@kZ18qE=?x8f$5&6%|XTQa^u~k;t+;LK=r^JgSQv;rP|{7E8s#1j)CDATSUJ`?6qhXU$*qJvD=Gs##$iq?uWZ z&-uKmADwlRl`&gH%zRWDJi#RPOmhJHP`9=>E2xkamZ_qSaS6)k?=D?p5DCcUiJ-=z zIi-eTX4A-fp6!Q-NPL4)9jNkc&zCMGPxq&4UnDX_+OXBI*$R8o2!E7{njGx{X536H zZ12nDvY5u1ZNLtzw-q|$So#82JnCmPA5f)z;~&80d~#zgR#MN!9n{^V^5cHptzYv; z4tb#BWLB}~ybJ9b&SaRQ;S)i8u$0X!b+z>MQuEM;8IfMZZapo6&mX8r#6UhQuKFF{ z4XgL6QD6GAFf1s5*3!S|WGirZ#uBDqCf0$T_&SjJPtfng2VzaG^Or&_Q&^W?Ts;^N z*(beah(M#AZ5cG0NoERBGcJ2{rECSwDA9__P01kJCI!HR4w*9m zJI9$3Z(g_p6Y7iL)2(iTX<6^ zZ*yFIUj}I0pr0C)Uo!MpvwaO)_ZTVh?PSdSodb6D3tH`W@;$XlPYdCh9RsUiqWS)%>6SKM5zp&7UhxE0?P)W(VFr zb5Jf7pRkUTj=;wYt=cewUuI@bZOWU4GQ%D3x5}d;ZAx&kSErc`(jy6=@qad&<9EV< zdoG*s1&Um2RBNCk#MK?R@UZts!1{XVqpr)okl-!Bw}bhPYYEG8lSR0{V8M4`Ia#V3 zJS~>SlIP;V{3tWj4;N==`r-Tq35k$dMhFcgaEqOBC$pkRtqX+?Be9?;vLAq&O;O%? z?c-m01RLO~SZbA;dyT|fUunI9Ap`@hR0sv@+?=lV;1+z05pNRE2{;-swV zd9{X9ZJS!<$h)+gHtG+TLZtDt5*e0Nv3xC+wZ~Z}7lpgT7#*!WHxj$1C@B_*dJg2G zMqxhtI{=g+zppguUO5gRDwZ|OUg$8&*MY5so zxx#&3B>43pk%o0wSmRL753zggT#K5fP!^B55jnd;fjI?QyWq#^yPyjfbhUewYhYKQ z#KuBd?8>Xpln24qSyffafnl==t(I!<4CW8nej-gF_Ypn1l@>JKo@T}ZgR6r5xrpe9 zQRs62ML)a;OQ(A%=TyCPttYL@O+|-$yiTjbL9Ihban2vup8iTElOcRjDTR z&!7L8{;J1K@><<=J5j~y=}G3&xl7MKukPchSW4D_U4a*59u82W6e?klO5mTZ8QNF%n1&{AYSHk=Oh|CY*QKSUwY5T>C#Hc0Ss{T) zKVWB}?E8KME+pY~&y1R_Upr4q%w}ostWkJgQW7UTa_!x7C!LvN{IEudKZcRld%I}} zdOf!JM_e9r3g8<2$RuqG+_xpIzd+-qOcEIYgWlWU+E1h=PoG~y&;kGeFAs8*yeWHM z!bvJdF}i7wp-Ob#W({TG;}VM`+v$0A21Vega}sIOx0uQ$`rhkAolvysmQvA`A@ z*{rat0zvr;|6ZO5a~GpylBdsL`aq#-L8W)M4XRkAocqkvdJivYdRpiTq(0s`km&!g zG4k2Zw*rw=8Vv<7CnR#N)d?}{$~r#nTj5(M8APUF&1_wQ_#ScFB-D!EZ0-ySmseCr zMn-DUXCuMIpnT?XG7S~(*C@$9bR?X6#wEE*m@IQ{pU%Qt*0XJ@GOr?2Q`ubyBZox> zAr-P~CJUi6a?9#}5N=Eo`@rhjg7&Vyq!l3JJr@f_h0{KxQHW9GVi@yfRTZ#b^LL>1 zk-|oFz#azi`OaS9^6%}zj8WUK{aH$wS^7S#wg<0qfNk^4FTagK773b)z8!f&*c@@^ zUe61SQ%#D)U+t-HpJds&HbuEu5Pp~CxNzu}{veC0@FyqhwC;n(Stv9*$G&v1>25CZ zFRjycn#X7Xux20r#B54(@~f3RPF=E)?5{TXRVM zT6BRqwKO?ds>cMdO< zK6MA&AJ9h2$*9jum7;`*z0%RG&Q))Rsskg#F~gN^W+~5=R5Uw3yrwkH#D7wkewrWa zhg%=q-S^XyOqL?9`KKzvTtf?VY#F;$0RU4%?Z;2CuKU-~o2#IKmD%?3Iz1*#E%Iq> zPnO6{bN}~2XWm(2 z-}Vc{2=!~WVYn3w>X4B}L9-?(yQ1x++4$y-SjHxH|}yg_|8M*z;~H@+xUGr z1bh}iSAY(maX*F{6D-b%RK2sP9?U3!vEw+4NyF;Tc*MA6;F~u>qA*1_9R0a=uEsn= zNIJl&H1lAI5jdDxN>!5^etI^^>N#7$LJ54D>gILeU?0eUH1RW9Ac!MyBNL3Tr&e)h zG=`KvK>*^V45>c+Nw|EyBbFUGI$MdVM-|uVG5d$j2~R|O5_&XiDZODFI_?Vq#S0P+ zVdn9ulI6~t6!0=dmY{otfL@7)&F&G^*q@&Nnx|3&P&9yOyOD$st`h~><(?pokMxN! zjI=b#Zb(g3%lGsqrW!sqbWrYX!Iaa40+NPGb^eh%8`Ksvm zsEvX}##B{RMUk-f$UY&20%6h_8`|18ON_hYS1O-+Y!Xq4!KW~%L^lXr9=A;%nt0w? zF%518xkNPC`DM4Xa1Bu{crrY4;nUK1BZ$`O2U3yjGSHh6Xy)R{cVxGpZg%XZjI!v# z#ap$TdHMwE*GGcx6-3h5%Ucl&T2Ww4FCZ7Jul2T2pS0KVqM4T)nukPJ(c2SFUwhgT zg1@qDkUvLVvMyn(Y#T({z;d3IdFK~vzolBrGAT>)uEA~ne!1;?+ECS)&Pn5^M`=P123rIyG%Z9wT_=A-DiJS!qK#XF^8oPfyMeX|q9rS^w$COAU zR*X~n9(hw|!&3r;B9XrJxnnMm4?eVqY)E)K--yL2h#OENJR&b`0Q>V3kls{(F$Eyf zo2#quu&g`dBKG4ZH|CV#!VR$`wtM@|6TPn~*q0~mOI^W-0ZJ1~2J8}^NNZKsrSU9a zbkLs!xDPC1j<3q)-Elh#1p$Tf;)P`g69@584763`hcZ?-v81Zy#m+kW1HE1T%U`Wc zmM1u{g&S+M_*Q>Rc1s4X>(<2h3CUC2T*;my*k}&cww(=%3Cx~;t&g+kkUSMYdZ9Sq z-RP3|A56{udiZKI2QcXh{q=g|TGvOj>LYa`8Lx6mI4B2s5Iu4!DP>w_6xkA*%I-n_#{VMz{2Ns1|0fr28cSTO1 z`2k9t(st!{JyVz=R?|lk*1GbWt`=$1thMp)#?31m*VRd~&o_WhBjZ~o4}k9iN|7rx z!9;uK0oD__`<9^t44|xTTt4ZR>;BT-+pT}(vBDZ@&FxBpMA`aANd3E;V7z|Q?_%Y- zt$?-bl;c&frAI9{ z=P`bg>a&j<^kH9B(+0pN#IwBm$0jPyMym;f43i@*3-|0@_p@l`4d1FYNN%Yy{HR1h zjLp)Hx@$oqxOv^uVQ+Ez+06q9t^9$A<{_v~t^@k40a?7T@eYo?T9NQ3q#meZvJE*D z5Sy`Y0N1l4BxcM=-u4QF{US07&#N15#d!v?*b8H^DH=p=fjY>MCI00L3Mhl22ys&u4uFSAILB zN%9+939GJhTmWQ{M-YGh;uQC1ughH}CDL@t=mKfOUYsdS%j>7Nfzf>G=Se5~)RYwF zo`;bR7d?UWhor{+N@Fl^FJ8J`W%R~a)(y$Cyp=qEt)u6wyUhrI{-u8Y@ZrPwo-59| zLr~&Ejd}Ex@Eu(ISk|zRx#!39Fw#FfQN>0Npe{4ac6z!4xdH%lJlG$UkD&L(l9336 zLjnBXaBMe~-94<&xZ4K4Hv70NH~7p!Lg(Ei=1(Iy3_2%r=il^ zo5#pqWFLG~FUNsYh%3QyAZtxm#@+XKES8UcY0>-$jnXSw>ulQ+Mk&$D1pK=w;)=LL zwxZ7gR3)%5fI5wuVgk(!3Y;6~CMPF>b_kFo!OuF*vrmh-8Ib9YDR$5=yMF}!%4V}I zF<*cA{#p?as{Y$mTUcP_7_!1-E-pyRW1}0&x^TOv+(%Cp%L)VZmw{YlRkKxyUQe{? zy=CaFr^;flO#iSkc>nKqh7hH+fE_9RTz0#sJK}BUxPy~JfH~uF`rmp?D-~VFvsCTQ zeDu@FgjKctibPE#72z}OHfP01!q&6_jc<3H|FJkTgAhExYoBl;osJIb+8X})tf0Lo zLuLD5Pvtl(M}$ZN0<64yeGc27{P*|Ljbz2Ed4+S1TV0N`zaDq&0tK7eD(G8~Flfxp zRd^z(AS!@oljfUlxxMznb4v8%>9Z#7ieYFvAOpu>iStBDeB+G;p~8=GPf@e#G-`UqZo@#7k%JEtOp-_fddc- z5PIpo8^9^UvfJZvv%Oxn`X_**qXoE(Zpk@OhxVcTZleCMul%j=sKO4$pJ!`IreBOj ho9h3UABS()ns9ozj!H6mfFphd2Rr9WwHJc!{U55TX-EJ7 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00001.png b/test/snapshots/stax/test_2to2_finalize_1/00001.png index d696375426668d2ca37b9c315ced79c70c713860..b409b61683a8a5f9a80fc1d48ee918b9c9be048c 100644 GIT binary patch literal 15893 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

3^vf-Pp+T} zPpT0Y?Ryb@_H>!vpvB6d=bSnXiXzM=2b!q#)^=^IH=i6daC#eX0teU@w0@W*0xGOd z-mUZ`onw9GE3^Ka>SWWL9z*yC*D#$tpxxoO3|;}mDPXj!T3E`+s?weyS!7%zfueOQ zvD@WKyOO_}5J12#2FPE%h^fg;QWlo3TD7wAJvTzQZg_E`8|~-vYB%oyMDX^*WcC=< zkb!q9W@uW7NZD33Lr zdSh?7D{3bO0?iL;kqP5K-!!vX00i3}i6moqu}6aRkd}9l zgvxfV4a?02hlbLt&qEyg0P}2vP>kgzexcu)BUEzJ(hBn<$6VRivn>&%`~4BXoD8R? zk*|Zn0AkU?0>ZTP`LF?oKB3>e_5|+Dsq%w`iw%d~KF0w;4F^^%0QJ_;zY*&e$xX<2 zW2lW$^tg#( z6F4PH@O$T=7UJ5HrH5By{{6LEsS+gJO7%Ng$eLHcff~1~lKl*R2?HS;THa?n0Jgzz z)UEoi>e6_Gn2zXi>oa67hYAq|zN^t6XUA8L&@61xe@dv|7o9qRWRiA%l6z z{Ns^NUUcq$9k&14FS7lw(5#Gx=-9Euohr9T?i^-Zrb^F+b^=pG#_T~7Jo5Z~qqR}- zvH0+kRv)ZFgH#)pP{#yoZ{9q^fnQC0ATbm`@xlj6E0j!9Hd?*Q@D${HpI;EiAAV zp+5}&yoS^s&S~Q>Eh$fUI)2s)wP>ZdtNHxXaqy1?GyAu;D3{Y@cqH1uOkms=Zle|2 z>F#Ngb0CAtX1Z+4RbFgQobPKsXfws%W`YoSMIIjz;}e$>-rx%)%H#|Cab64eqHC+ Zag{B2lT~&f;J7!7p}yJO%G*va{uirQ*_{9Y literal 15593 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 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00003.png b/test/snapshots/stax/test_2to2_finalize_1/00003.png index 7a05bf7b31c3fca94a4a464ad8709d1c20600e36..cd2f52759f160c3e2cf6822395ea675b8c84a851 100644 GIT binary patch delta 3463 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 W_hL-Xeg|0tu3wG^A8R@qfAhb*jea!% delta 3069 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 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00004.png b/test/snapshots/stax/test_2to2_finalize_1/00004.png index 82497e000274af8643c9f7f7857adb7ae5bdad70..30b434c51f5be56b80b57118f490c5428212d705 100644 GIT binary patch literal 10937 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 10347 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 diff --git a/test/snapshots/stax/test_addr_display/00000.png b/test/snapshots/stax/test_addr_display/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ffd9129898cf04120c107e8397875ec0fdf173d3 GIT binary patch literal 8746 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display/00001.png b/test/snapshots/stax/test_addr_display/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..27f08963160773a254539075331f32c71385355e GIT binary patch literal 12851 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path/00000.png b/test/snapshots/stax/test_addr_display_unusual_path/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1d78f65f239c1376d014b3c3fec4b364a0aab718 GIT binary patch literal 12803 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path/00002.png b/test/snapshots/stax/test_addr_display_unusual_path/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..89fef03daf1f47923d49ff72a90d8b500a7d3b48 GIT binary patch literal 13836 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path/00003.png b/test/snapshots/stax/test_addr_display_unusual_path/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..f59899e9aa967b23177d83aef0c8c2c9041eab91 GIT binary patch literal 4615 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_decred_sign_message/00000.png b/test/snapshots/stax/test_decred_sign_message/00000.png index c496c71f6f8e58c181cea00b2422ed58a438e61a..df0931d2dfb94e81158302fc89ff1913c66281bc 100644 GIT binary patch literal 8791 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 N0qL9E!Q66=`9BHovW5Tv literal 8114 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 IYwpkf8y3NR{Qv*} literal 12651 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 diff --git a/test/snapshots/stax/test_decred_sign_message/00002.png b/test/snapshots/stax/test_decred_sign_message/00002.png index ee463b619fd13d09cf916b998de1d5f07b74bffa..abb4b7834dd1dcd0d3d1089d562d4519837db08e 100644 GIT binary patch literal 9483 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 diff --git a/test/snapshots/stax/test_decred_sign_message/00003.png b/test/snapshots/stax/test_decred_sign_message/00003.png index 30e6112a09738229bdaa77ddf1ce9c929d6a9454..80bb82656de9e778e000c10fa3efdea8bb5c71e0 100644 GIT binary patch delta 2401 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 bX%_wmGzzi~o|LAf00000NkvXXu0mjfngyI) diff --git a/test/snapshots/stax/test_decred_sign_message/00004.png b/test/snapshots/stax/test_decred_sign_message/00004.png index 82497e000274af8643c9f7f7857adb7ae5bdad70..30b434c51f5be56b80b57118f490c5428212d705 100644 GIT binary patch literal 10937 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 10347 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 diff --git a/test/test_show_address.py b/test/test_show_address.py new file mode 100644 index 0000000..6b72b9a --- /dev/null +++ b/test/test_show_address.py @@ -0,0 +1,70 @@ +from ragger.navigator import NavInsID +from binascii import hexlify +from pathlib import Path +from inspect import currentframe + + +def test_addr_display(backend, firmware, navigator): + packets = [ + "058000002c8000002a800000000000000000000001" # BIP32 path len, BIP32 path + ] + + packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] + + # 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key + # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 + # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + + path = Path(currentframe().f_code.co_name) + with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "stax": + navigator.navigate_until_text_and_compare( + NavInsID.TAPPABLE_CENTER_TAP, [ + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, + NavInsID.WAIT_FOR_HOME_SCREEN + ], "Show", + Path(__file__).parent.resolve(), path) + else: + navigator.navigate_until_text_and_compare( + NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Approve", + Path(__file__).parent.resolve(), path) + + +def test_addr_display_unusual_path(backend, firmware, navigator): + packets = [ + "058000002b8000002a800000000000000000000001" # BIP32 path len, BIP32 path + ] + + packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] + + # 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key + # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 + # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + + path = Path(currentframe().f_code.co_name) + with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "stax": + navigator.navigate_and_compare( + Path(__file__).parent.resolve(), path, [ + NavInsID.USE_CASE_CHOICE_REJECT, + NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, + NavInsID.WAIT_FOR_HOME_SCREEN + ]) + elif firmware.device == "nanos": + navigator.navigate_and_compare( + Path(__file__).parent.resolve(), path, [ + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK + ]) + else: + navigator.navigate_and_compare( + Path(__file__).parent.resolve(), path, [ + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK + ]) From 619e493df7b4010e6ec9eddd270b113e1a6d050d Mon Sep 17 00:00:00 2001 From: Alexis Grojean Date: Fri, 15 Sep 2023 10:59:11 +0200 Subject: [PATCH 39/41] PR review --- src/ui/ui_main_menu_nbgl.c | 12 +- src/ui/ui_pubkey_nbgl.c | 8 +- test/conftest.py | 4 + .../nanos/test_addr_display_reject/00000.png | Bin 0 -> 489 bytes .../nanos/test_addr_display_reject/00001.png | Bin 0 -> 492 bytes .../nanos/test_addr_display_reject/00002.png | Bin 0 -> 313 bytes .../nanos/test_addr_display_reject/00003.png | Bin 0 -> 341 bytes .../nanos/test_addr_display_reject/00004.png | Bin 0 -> 340 bytes .../nanos/test_addr_display_reject/00005.png | Bin 0 -> 336 bytes .../00000.png | Bin 0 -> 431 bytes .../00001.png | Bin 0 -> 392 bytes .../00002.png | Bin 0 -> 427 bytes .../00003.png | Bin 0 -> 394 bytes .../00004.png | Bin 0 -> 516 bytes .../00005.png | Bin 0 -> 508 bytes .../00006.png | Bin 0 -> 344 bytes .../00007.png | Bin 0 -> 341 bytes .../00008.png | Bin 0 -> 340 bytes .../00009.png | Bin 0 -> 336 bytes .../00000.png | Bin 0 -> 431 bytes .../00001.png | Bin 0 -> 392 bytes .../00002.png | Bin 0 -> 427 bytes .../00003.png | Bin 0 -> 336 bytes .../00004.png | Bin 0 -> 516 bytes .../00005.png | Bin 0 -> 336 bytes .../nanosp/test_addr_display_reject/00000.png | Bin 0 -> 701 bytes .../nanosp/test_addr_display_reject/00001.png | Bin 0 -> 364 bytes .../nanosp/test_addr_display_reject/00002.png | Bin 0 -> 365 bytes .../nanosp/test_addr_display_reject/00003.png | Bin 0 -> 368 bytes .../00000.png | Bin 0 -> 500 bytes .../00001.png | Bin 0 -> 460 bytes .../00002.png | Bin 0 -> 496 bytes .../00003.png | Bin 0 -> 453 bytes .../00004.png | Bin 0 -> 767 bytes .../00005.png | Bin 0 -> 364 bytes .../00006.png | Bin 0 -> 365 bytes .../00007.png | Bin 0 -> 368 bytes .../00000.png | Bin 0 -> 500 bytes .../00001.png | Bin 0 -> 460 bytes .../00002.png | Bin 0 -> 496 bytes .../00003.png | Bin 0 -> 368 bytes .../nanox/test_addr_display_reject/00000.png | Bin 0 -> 686 bytes .../nanox/test_addr_display_reject/00001.png | Bin 0 -> 364 bytes .../nanox/test_addr_display_reject/00002.png | Bin 0 -> 366 bytes .../nanox/test_addr_display_reject/00003.png | Bin 0 -> 368 bytes .../00000.png | Bin 0 -> 500 bytes .../00001.png | Bin 0 -> 460 bytes .../00002.png | Bin 0 -> 488 bytes .../00003.png | Bin 0 -> 453 bytes .../00004.png | Bin 0 -> 767 bytes .../00005.png | Bin 0 -> 364 bytes .../00006.png | Bin 0 -> 366 bytes .../00007.png | Bin 0 -> 368 bytes .../00000.png | Bin 0 -> 500 bytes .../00001.png | Bin 0 -> 460 bytes .../00002.png | Bin 0 -> 488 bytes .../00003.png | Bin 0 -> 368 bytes .../stax/test_addr_display/00002.png | Bin 4615 -> 7806 bytes .../stax/test_addr_display/00003.png | Bin 10937 -> 12851 bytes .../stax/test_addr_display/00004.png | Bin 0 -> 4615 bytes .../stax/test_addr_display/00005.png | Bin 0 -> 10937 bytes .../stax/test_addr_display_reject/00000.png | Bin 0 -> 8746 bytes .../stax/test_addr_display_reject/00001.png | Bin 0 -> 12851 bytes .../stax/test_addr_display_reject/00002.png | Bin 0 -> 6545 bytes .../stax/test_addr_display_reject/00003.png | Bin 0 -> 10937 bytes .../00000.png | Bin 0 -> 12803 bytes .../00001.png | Bin 0 -> 8746 bytes .../00002.png | Bin 0 -> 13836 bytes .../00003.png | Bin 0 -> 6545 bytes .../00004.png | Bin 0 -> 10937 bytes .../00000.png | Bin 0 -> 12803 bytes .../00001.png | Bin 0 -> 6545 bytes .../00002.png | Bin 0 -> 10937 bytes test/test_1to2.py | 23 +-- test/test_1to2_warning_change.py | 9 +- test/test_2to2.py | 12 +- test/test_show_address.py | 160 ++++++++++++++---- test/test_sign_message.py | 12 +- 78 files changed, 177 insertions(+), 63 deletions(-) create mode 100644 test/snapshots/nanos/test_addr_display_reject/00000.png create mode 100644 test/snapshots/nanos/test_addr_display_reject/00001.png create mode 100644 test/snapshots/nanos/test_addr_display_reject/00002.png create mode 100644 test/snapshots/nanos/test_addr_display_reject/00003.png create mode 100644 test/snapshots/nanos/test_addr_display_reject/00004.png create mode 100644 test/snapshots/nanos/test_addr_display_reject/00005.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00000.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00001.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00002.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00003.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00004.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00005.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00006.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00007.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00008.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00009.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00000.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00001.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00002.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00003.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00004.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00005.png create mode 100644 test/snapshots/nanosp/test_addr_display_reject/00000.png create mode 100644 test/snapshots/nanosp/test_addr_display_reject/00001.png create mode 100644 test/snapshots/nanosp/test_addr_display_reject/00002.png create mode 100644 test/snapshots/nanosp/test_addr_display_reject/00003.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00000.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00001.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00002.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00003.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00004.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00005.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00006.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00007.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_path/00000.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_path/00001.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_path/00002.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path_reject_path/00003.png create mode 100644 test/snapshots/nanox/test_addr_display_reject/00000.png create mode 100644 test/snapshots/nanox/test_addr_display_reject/00001.png create mode 100644 test/snapshots/nanox/test_addr_display_reject/00002.png create mode 100644 test/snapshots/nanox/test_addr_display_reject/00003.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00000.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00001.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00002.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00003.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00004.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00005.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00006.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00007.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_path/00000.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_path/00001.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_path/00002.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path_reject_path/00003.png create mode 100644 test/snapshots/stax/test_addr_display/00004.png create mode 100644 test/snapshots/stax/test_addr_display/00005.png create mode 100644 test/snapshots/stax/test_addr_display_reject/00000.png create mode 100644 test/snapshots/stax/test_addr_display_reject/00001.png create mode 100644 test/snapshots/stax/test_addr_display_reject/00002.png create mode 100644 test/snapshots/stax/test_addr_display_reject/00003.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_address/00000.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_address/00001.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_address/00002.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_address/00003.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_address/00004.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_path/00000.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_path/00001.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path_reject_path/00002.png diff --git a/src/ui/ui_main_menu_nbgl.c b/src/ui/ui_main_menu_nbgl.c index 34159ee..bfeb870 100644 --- a/src/ui/ui_main_menu_nbgl.c +++ b/src/ui/ui_main_menu_nbgl.c @@ -35,8 +35,8 @@ static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content); #define SWITCH_KEY_EXPORT_TOKEN FIRST_USER_TOKEN #define NB_INFO_FIELDS 2 -static const char *const infoTypes[] = {"Version", "Decred App"}; -static const char *const infoContents[] = {APPVERSION, "(c) 2023 Ledger"}; +static const char *const infoTypes[] = {"Version", "Developer"}; +static const char *const infoContents[] = {APPVERSION, "Ledger"}; static nbgl_layoutSwitch_t setting_switch; @@ -51,11 +51,11 @@ static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content) { content->infosList.infoTypes = (const char **) infoTypes; content->infosList.infoContents = (const char **) infoContents; } else if (page == 1) { - setting_switch.text = "Public keys export"; - setting_switch.subText = "Enable automatic key export"; + setting_switch.text = "U2F public keys export"; + setting_switch.subText = "Enable manual approval"; setting_switch.token = SWITCH_KEY_EXPORT_TOKEN; setting_switch.tuneId = TUNE_TAP_CASUAL; - setting_switch.initState = (bool) !N_btchip.pubKeyRequestRestriction; + setting_switch.initState = (bool) N_btchip.pubKeyRequestRestriction; content->type = SWITCHES_LIST; content->switchesList.nbSwitches = 1; content->switchesList.switches = (nbgl_layoutSwitch_t *) &setting_switch; @@ -69,7 +69,7 @@ static void settingsControlsCallback(int token, uint8_t index) { UNUSED(index); switch (token) { case SWITCH_KEY_EXPORT_TOKEN: { - unsigned int setting_value = (unsigned int) !setting_switch.initState; + unsigned int setting_value = (unsigned int) !N_btchip.pubKeyRequestRestriction; nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &setting_value, 1); break; } diff --git a/src/ui/ui_pubkey_nbgl.c b/src/ui/ui_pubkey_nbgl.c index d75f32b..1098a70 100644 --- a/src/ui/ui_pubkey_nbgl.c +++ b/src/ui/ui_pubkey_nbgl.c @@ -34,7 +34,7 @@ typedef enum { DISPLAY_TOKEN, } pubkey_display_usecase_t; -static char confirm_text[20]; +static char confirm_text[40]; static char choice_text[70]; static pubkey_display_usecase_t display_type; @@ -45,7 +45,7 @@ static void confirmationChoiceClbk(bool confirm) { if (confirm) { strncpy(confirm_text, "ADDRESS\nVERIFIED", sizeof(confirm_text)); } else { - strncpy(confirm_text, "Address rejected", sizeof(confirm_text)); + strncpy(confirm_text, "Address verification\ncancelled", sizeof(confirm_text)); } break; case EXPORT_REQUEST: @@ -72,7 +72,7 @@ static void confirmationChoiceClbk(bool confirm) { static void address_verification_cancelled(void) { io_seproxyhal_touch_display_cancel(NULL); - nbgl_useCaseStatus("Address rejected", false, ui_idle); + nbgl_useCaseStatus("Address verification\ncancelled", false, ui_idle); } static void ui_display_addr(void) { @@ -82,7 +82,7 @@ static void ui_display_addr(void) { static void warningChoiceClbk(bool reject) { if (reject) { io_seproxyhal_touch_display_cancel(NULL); - nbgl_useCaseStatus("Address rejected", false, ui_idle); + nbgl_useCaseStatus("Address verification\ncancelled", false, ui_idle); } else { nbgl_useCaseReviewStart(&C_decred_icon_64px, "Verify Decred\naddress", diff --git a/test/conftest.py b/test/conftest.py index dfe1f85..941d5d5 100755 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,9 +1,13 @@ # This final fixture will return the properly configured backend client, to be used in tests from ragger.conftest import configuration +from pathlib import Path ########################### ### CONFIGURATION START ### ########################### + +ROOT_SCREENSHOT_PATH = Path(__file__).parent.resolve() + MNEMONIC = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" configuration.OPTIONAL.BACKEND_SCOPE = "session" diff --git a/test/snapshots/nanos/test_addr_display_reject/00000.png b/test/snapshots/nanos/test_addr_display_reject/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..c29cb65dc7a27ccfee3e9f94ebe8b6a16e2c9450 GIT binary patch literal 489 zcmV92!LtM^!^XrqFFSC0lHGKwEi!9nm9 zDjfjeJbwLd+b1l>G*IglsNTi4&(YJ(k|Sv1ddL}qClBs1Fq=M`_y~YMw~8|g@!7R5 zJVrlgD?9ivVVu-dj}QN-V0tj!0Wm$2n7}1RP=b8a@%UbH5AG-T;7-!| zcjC1^mIlT0px4?FJ$Uk zap4{(6Z@MbELC{>Z>X}{yysvRGa`X#)e#^3HGr;6SS-lEe|z0xeV%xikXP(njw;h; zo+k&?nz|CPk;IZ$M)7%i-oNZ;1H-Fb|Mm#*cmX-+No06XBq&3;`>!eHkV@1XoY!6J zUxf1Px#tzF^x^t)_^ZGF*d?q+Ksk)N@c02uP9%>&UU^og>(g@Pzj(=C=?2XSe%EgOBlbR{XDK8JAn53 z(s&GQdP1+Jagji;Md*!RfZu2ZT`29|TDIN%w{U?*0Q)@Ah!#vAOad8=Oh5dDN(TTq zkINso-C;6A18Gz=O6VB?w%v!P8YwBraXu)ww9M1i7>G?NnKvb<_y~Z1w~CuK@>#)! zUuJy(*kZ-g3AYwxvet_lk%YNTxTjPW&hih(M^3(XOi#+)8Uul!v_8CP0VJ7Uwf+mi zn7XW=j9P;yQCa9o+>K0*p~Hih*U1cBM{lGS>dDIeB?(=zD6*v z!DxJZ1Pl$-^Ln&5&TZpVj`bD!ElNJz6_i_$NsbqvXEDXZ5&>Spo}V;wU`7SV?Q0000JK&k-#&AMe`>s8y^Y8CM+Iws z_r}c)bCy21ntveN+HsoO-J6g8yq&Kgu%GedZ+5qf8>THgrtPsLqtmjlKdVG((Pxg& zFa9(f4q;ujtl-~zAwB(IRJ?|?}_cO1t z>B$kCv@u-5wIyBtp+%_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_reject/00004.png b/test/snapshots/nanos/test_addr_display_reject/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..9c7e7049cb3e9bcfb1601ec510ee465d38229d4d GIT binary patch literal 340 zcmV-a0jvIrP)b=%MgRq*37h4eRxPbkJCLY|1VIo49_}P}TKpH4$L<8?X{t;p zy+UQc_4@p%0?~E_&igM#?#L~IOHR(-<@sYotiy&C*Y&GII0yeh-p3zW9cv$Q0k>6Y_)5~SfP=m zSMUtz)%Ex|-o}7!H9hbQ(8{%C?kQVa?C`*Uj-J(h>P7(Y#?ZWvi?6}@n{fGLp>YTp myqR(V_$?>^<%seR_VWh!2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00001.png b/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..527e9503ff3ef865833a68fa790ed5508879f5f2 GIT binary patch literal 392 zcmV;30eAk1P)Sv(hNI<-UGnC+_tY%ZE#BodRvdJ zepVuJHM@H>6u4)R|?_?<%9MNiRj@avQ+>B#8Bl*shME|ll z&H$Earu+U$6Y;&JL|eD<9dDNb$eGlTQY+e9%nX+lwEwH?xb_y&kD$JkOx5|pYMU$9 mX8l{6`a%l;00000bm9x>I6;gRz*QIk0000(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00003.png b/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00004.png b/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..496b56ea99d854afa0e23b9d2c516a8e7b05936d GIT binary patch literal 516 zcmV+f0{i`mP)Z91h1^>|5O@L%(zNeG?`RlJF^0 zegfk5jIW5WlYquV^T%)+5`JedpaQgelq_rYD~Be3IQY2}pBse5vn&dYQ9MCS4uYSl zvl9{R+uylc)&ZL-8mM-ONH1Vn$MA%4ND3ObpDc&O%oBY~%%<1I{0N};v6^R;?93i} zggY@g0(gK2iD;vu;ZgxDU>U``}Et z_0PnA>o1_5dK=3w;F-`EmEHfiW-1I5inqh~%$bPX2;Q2_xk^7JiB1BR_;&Nw7**{0 z8l4}zQ)F|)Nw%pWD<-Hf#EPdI9H`Yt_&$eMNn&Ia9mebMOxYyaR0%h18#ESAJ5>`l zAC8DDQD}VlS35oGXmUWYf(Ms3ngo1BWb6!=^Z?jky#qAo^MA&uJ!>(6_^&Nb7Ds_< zR3_Qlir^)6D#5MaS(*>8?7^;WRdd%QX+}WX6;o8>jZBfB$kkpkJz@wq@#rA5ZAv&v z#|OqO7P)rE*N!Os?r!J>dXsu3{Dm;C^R}9&7l*@fPrLvP;b{a030K(w0000iZG=M}5JL)(NF)-8#8~WG+aqKAmDTs{_=p4e z(^xeg1Da<%^$0I2ph=9U;{)(NdI1$qzoTSXn|~$_@Dm_@?+}uJ`45w!jE6H0e?!>; z0QT+JkINchOw~c2B~T^u9RQX!Mo%|xNkM`3klccq2V)G(r(Btt64dw;0KaWD&TO)0 zjV(Nx_W@uTOV15P32_-dB|^f`_Y&3?waG>OhvOxc?-|`jg?pny_)71?OaZVs-|GDd zA-Fode={-$Pa?C>lQ=t>m7!wcMFQij%(Piz0jkXv%S2#xCrD)_{LE<@##d~;-w__; z;_X6I31PP+t0YDnS(7;1oW>HRq^hmRQ=8S>iqNhwh-#e6%Mqc{=3cxLjkr}^?!Wf7 zBFc09HLUD6G-<=Bnh^WmYEq^&oC|%5H3mS;16(H$PslJdwcLr={WcDkHtcpZ1|US& z*dRemx^uF9BYI0nq)I2ei zo5nDBdIfKb@nHgImV(#60AKF`PHEJgEor&@6CB7Dpnkt$%nH_0RJjFZL$t)S)x+rke? zzTssvvL%y@y_qqKaPK872W<(i=I>6N-nqc-Ntvrr3HVC&X{G{{V!l=V2~nhm`kg@y zMuJ^vB!S<<@~X0W%`h7xJ#i45_6!;7e0z$RLYI@U2`^AzBTfNS3fF2u2ws5rjQc~z q3SI;O+n=xkhJykC00000fC22sDaOL^QLp;|0000_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00008.png b/test/snapshots/nanos/test_addr_display_unusual_path_reject_address/00008.png new file mode 100644 index 0000000000000000000000000000000000000000..9c7e7049cb3e9bcfb1601ec510ee465d38229d4d GIT binary patch literal 340 zcmV-a0jvIrP)b=%MgRq*37h4eRxPbkJCLY|1VIo49_}P}TKpH4$L<8?X{t;p zy+UQc_4@p%0?~E_&igM#?#L~IOHR(-<@sYotiy&C*Y&GII0yeh-p3zW9cv$Q0k>6Y_)5~SfP=m zSMUtz)%Ex|-o}7!H9hbQ(8{%C?kQVa?C`*Uj-J(h>P7(Y#?ZWvi?6}@n{fGLp>YTp myqR(V_$?>^<%seR_VWh!2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00001.png b/test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..527e9503ff3ef865833a68fa790ed5508879f5f2 GIT binary patch literal 392 zcmV;30eAk1P)Sv(hNI<-UGnC+_tY%ZE#BodRvdJ zepVuJHM@H>6u4)R|?_?<%9MNiRj@avQ+>B#8Bl*shME|ll z&H$Earu+U$6Y;&JL|eD<9dDNb$eGlTQY+e9%nX+lwEwH?xb_y&kD$JkOx5|pYMU$9 mX8l{6`a%l;00000bm9x>I6;gRz*QIk0000(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00003.png b/test/snapshots/nanos/test_addr_display_unusual_path_reject_path/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..4d13f81a58e4d37341dae89c3ed5deecc9a8d70e GIT binary patch literal 336 zcmV-W0k8gvP)2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000Z91h1^>|5O@L%(zNeG?`RlJF^0 zegfk5jIW5WlYquV^T%)+5`JedpaQgelq_rYD~Be3IQY2}pBse5vn&dYQ9MCS4uYSl zvl9{R+uylc)&ZL-8mM-ONH1Vn$MA%4ND3ObpDc&O%oBY~%%<1I{0N};v6^R;?93i} zggY@g0(gK2iD;vu;ZgxDU>U``}Et z_0PnA>o1_5dK=3w;F-`EmEHfiW-1I5inqh~%$bPX2;Q2_xk^7JiB1BR_;&Nw7**{0 z8l4}zQ)F|)Nw%pWD<-Hf#EPdI9H`Yt_&$eMNn&Ia9mebMOxYyaR0%h18#ESAJ5>`l zAC8DDQD}VlS35oGXmUWYf(Ms3ngo1BWb6!=^Z?jky#qAo^MA&uJ!>(6_^&Nb7Ds_< zR3_Qlir^)6D#5MaS(*>8?7^;WRdd%QX+}WX6;o8>jZBfB$kkpkJz@wq@#rA5ZAv&v z#|OqO7P)rE*N!Os?r!J>dXsu3{Dm;C^R}9&7l*@fPrLvP;b{a030K(w00002~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000KXnwA0p00000z-Mxv=Xsv~j|};@ z<2&1cQeF9Pd^*HWwgD<)Jj7}^j^i3Xj)TbfN3uw+0OC+m4a7C#AW>3fL`Rdkd}Ke5 zr~u+DXYR)|v>w+Yx|94KP;O|dM?>j3J-7E{2B1E9yA@n}Iv4ijsUh>s{il@jmAJOO zCy0GgYo}U9KfehB00000fEUhJ46&{rW5oWnE8iY{yQYfTY-2p~;?hpbzo3K>@?KGak^BXkTk(?LKqE&|R zS(lxf_i*{z=ho)2tuwtbcl!u2Q1P4q>R(qjQ%C6 zhAttr6`fy~BgQQe*3K-GEYYSNqqNg#S2%tU(<0Avq$s})sUHPSMq~lvM5&*H}4o(j$uG^A&h zJ-Ngz8K{6&#lC;j*u&`7G==y#qs_^kPHHl j3<3ZE00000z~}J`zqCQ$s2e_`00000NkvXXu0mjf@^wc| literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_reject/00001.png b/test/snapshots/nanosp/test_addr_display_reject/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=YMjqtrV%Nn6esuj!jIMi}Btw`sohxwi1&U@}K{{10Q-!s%eVxF#kF6*2U FngGM>p?d%T literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_reject/00003.png b/test/snapshots/nanosp/test_addr_display_reject/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..9088cece139d94e6aa44cc37a3f242f8a4c18e2d GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-&ba4!+nDh2Vv{17Gk3-<{ z%X2sUSKT?i&fxKdh7SHo9N%lUh6r#TIkX9=2L>7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00000.png b/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4087dd89f1ea53c9044584d11d3430ab40d0856b GIT binary patch literal 500 zcmVocNL5GvWu!S3>VMP zc<%ust$p1=EY_L^4~mK6l_Dhl8A6E9H2;|xQ{vC_DT?I!h_dzVRmk;00QxYuf zz6Ok6-#jIl_eG`H+1F3q+zp*!gAuV-R~JpDlGEirA+AeN6wR*vdV( q?f1vc6!cUu0000000000EaVsXKV)@JyifW70000}z` z?&-JIox!g;vLOvry@8CZBkwSL9L1fda<$W}qjL@#qs_kU?{~=(wEhj~N%v4Yw#t`z zR~yORJO{g$pkwXC-;sUA?k!h)E7=}^8hg2Oy=-6BX>YXVT{QKc4euALCYkKJQBqCz zoiPV@Vimd*zr%MTy#N3J000000000000000z&8JPE6>4Z7C4vy0000{edz=FR00000K$-X6dp~w|O@D7U zU_>#>a-k2z60q-k*hs>C>>d}W5KDk7i5^y%-)Xjld0)pb4M|UCw0034XH;vQM2=9FK zePpUB9Tg>&&XiUu+}vs5CbcGUnJ=(e&K<$Jdl-nz{~d=+KFGx7B->%5|7>1(+`@2s zd|7@r-)%M{xhuZd_G_O)!0+n;`9}S0&r0Xn#lyAN>upwdNnFTwY=sAEKE1^!<@sU6 zoZ*NXM`nx9ndBhpu<^nAEsMKp#1NEt?AiawSOEaQ5+r7pmn`w?=*psIe6atre1Y@U zrA>ML>y$nJ8#7tj!#?ss>}n{@zeF4M!Ur*P`N-3G%L+cy1Ka}ZuVdEj0rkbp%1hX_ mMx+leZ2|xQ00000X!-}bzH^FOl`lL10000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00004.png b/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..b79de80ccc770decb63e97d35ce1ff63ebf8e4ec GIT binary patch literal 767 zcmVRQCbW-b>6D`{6 zlIyv}4iJ+CuKipO?TmXKy^{53K>5I-x;2#Eq^~`DRyv@LybT3MOxKl>bsE&UXZ$Ip z{9E|!I3}3qq<5TpEBgM2Fd>8xLdbXGrlI0`;^k^_vKX`yiK8hnhz`xWLj8>An&8l4 zn}_O;w*6}p{Are(N}1OxZrBzgAG%KuR0{AWJbGaURo-DOsJptshKGb1D{I{j=iZ^r zozZnz)neOLxRDt#E-`FyvUJ!P>M*@HDs|Gu2Vsx?HV%&g83*VHE{p&l?`;C}iAdW| zxa17T0EZpmIbWX{v&QW031oP=IN5E5>)2f*lWM34e4+%OecjJVGfo0Zq(e$-Y-F?p zaw(=+tu;c&jrObH(DP(!or%V}bdZJyX2&LhMov#0o=uR&B58O1b7&We%C~qUwuex0gGl2T&jNgi>uYC~A8BbXz5V8RyAC734N=uB>3aoJ<=& zk$9ZfnkGmQ$G|G1*5ovd%5*6LH>Mr9E(8r5bATBKv`t7qQ>xXWYB3|;SYEa38FRoC zTjx5djD$O|x5J~?I41w=Xq`5sjRw0~zFK2Meg#TzeFuQyOvq9~o-9s6iQM>GVbbeg zhZmh_ikb;+QVb`McnKkd5JJd%5clv{J9`R`c_)1HTUeUMIN+7DUmoNDlaos79eB0_ xUcfE>Rlym|SBVdTJ76(%03n1BLI@$>$1h1y`Axivo}B;y002ovPDHLkV1gu^V%Y!y literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00005.png b/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=YMjqtrV%Nn6esuj!jIMi}Btw`sohxwi1&U@}K{{10Q-!s%eVxF#kF6*2U FngGM>p?d%T literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00007.png b/test/snapshots/nanosp/test_addr_display_unusual_path_reject_address/00007.png new file mode 100644 index 0000000000000000000000000000000000000000..9088cece139d94e6aa44cc37a3f242f8a4c18e2d GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-&ba4!+nDh2Vv{17Gk3-<{ z%X2sUSKT?i&fxKdh7SHo9N%lUh6r#TIkX9=2L>7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path_reject_path/00000.png b/test/snapshots/nanosp/test_addr_display_unusual_path_reject_path/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4087dd89f1ea53c9044584d11d3430ab40d0856b GIT binary patch literal 500 zcmVocNL5GvWu!S3>VMP zc<%ust$p1=EY_L^4~mK6l_Dhl8A6E9H2;|xQ{vC_DT?I!h_dzVRmk;00QxYuf zz6Ok6-#jIl_eG`H+1F3q+zp*!gAuV-R~JpDlGEirA+AeN6wR*vdV( q?f1vc6!cUu0000000000EaVsXKV)@JyifW70000}z` z?&-JIox!g;vLOvry@8CZBkwSL9L1fda<$W}qjL@#qs_kU?{~=(wEhj~N%v4Yw#t`z zR~yORJO{g$pkwXC-;sUA?k!h)E7=}^8hg2Oy=-6BX>YXVT{QKc4euALCYkKJQBqCz zoiPV@Vimd*zr%MTy#N3J000000000000000z&8JPE6>4Z7C4vy0000{edz=FR00000K$-X6dp~w|O@D7U zU_>#>a-k2z60q-k*hs>C>>d}W5KDk7i5^y%-)Xjld0)pb4M|UCw0034XH;vQM2=9FK zePpUB9Tg>&&XiUu+}vs5CbcGUnJ=(e&K<$Jdl-nz{~d=+KFGx7B->%5|7>1(+`@2s zd|7@r-)%M{xhuZd_G_O)!0+n;`9}S0&r0Xn#lyAN>upwdNnFTwY=sAEKE1^!<@sU6 zoZ*NXM`nx9ndBhpu<^nAEsMKp#1NEt?AiawSOEaQ5+r7pmn`w?=*psIe6atre1Y@U zrA>ML>y$nJ8#7tj!#?ss>}n{@zeF4M!Ur*P`N-3G%L+cy1Ka}ZuVdEj0rkbp%1hX_ mMx+leZ2|xQ00000X!-}bzH^FOl`lL100007f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_reject/00000.png b/test/snapshots/nanox/test_addr_display_reject/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ea3703ddc3e8d5b9b1e0d83d994e85fd5659e057 GIT binary patch literal 686 zcmV;f0#W^mP)ibk@H>1a_`m+a>e z5g?oe&i%d?N{@RZx|8#JKw7Y=UInS<^s{@<$pOeuUM>Z%HC-Dc^E9w|=K7OT`a0Nm zye63Yq_>@VGy3_PFd>8xLI`=|ekU-iwiA@ZzgF$bqis8#}{a^B7q5KQ&k}T zRI=0a9+R(imTn%~cBT(zwU0OkF34G7R!19pAvW~>N$CBPXzw?Cl%Mhn6&%V&8lTcs zQ|`g*apBu%Q|wevRdXY8N^9Qf$vcErjS*FDE(ko-nTN)F_!Ji)Ikn>526}>a%92tT zuC05Rdn)P&?z`}=t098a1t)2&syeiJv^cK{t6JHusvcV(w|kD&d+2#9^;&3f^zM%?1PcT~hvty=t! zsQ~Umcq6mKoMli66af=A$-kEkZ(W*3310k92_S?JLI@#*5JCtcgb+dqA%r}ZUl*%o U?#Jba1poj507*qoM6N<$g6>K^P5=M^ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_reject/00001.png b/test/snapshots/nanox/test_addr_display_reject/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Yj&LwL#RobX?V zbQiII^4uMl|Z~1l7yy12MZ$b&j z?TtJM^{@JVDT&uHZn5nzWh-TPv_J7m;jgq0f(|YbTZHdAM)myZxO-=(=&Jp4l55=A zUQcBF*M05wg}=Y7bG1(&{&siyl(&8#-KTdql}}rLm3hWhy}m5glJN5fpDsOd=_5x% z{HDvZre)46&g0e%{pDoXaPf-VTe-XJSGLU(Jj!tDNp8H)+;exzHoZ2kko_Ba_xXNR zr;WUGZIbufwyah@qN*6%Wc!qrE&9UV%v{IGH{4)eXE1ondwSC@^_ATTjUX{kS3j3^ HP6waunSk|hFqW?7)TH`Jk~9Gerv(6ecqmn7nn8uWB;3b zw{g88mtqOmX|1nQ6UyKSixvS1g}CmE5?ACG-| zpBvCv#x={;%P2FXMyx;J&mSL^`zg=uAmI;8wJYD@< J);T3K0RY{rqSycc literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00000.png b/test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..6ebf2582dda066ab28d4095a45b5b1a1a814312e GIT binary patch literal 500 zcmV#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000}z` z?&-JIox!g;vLOvry@8CZBkwSL9L1fda<$W}qjL@#qs_kU?{~=(wEhj~N%v4Yw#t`z zR~yORJO{g$pkwXC-;sUA?k!h)E7=}^8hg2Oy=-6BX>YXVT{QKc4euALCYkKJQBqCz zoiPV@Vimd*zr%MTy#N3J000000000000000z&8JPE6>4Z7C4vy0000P)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00004.png b/test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..b79de80ccc770decb63e97d35ce1ff63ebf8e4ec GIT binary patch literal 767 zcmVRQCbW-b>6D`{6 zlIyv}4iJ+CuKipO?TmXKy^{53K>5I-x;2#Eq^~`DRyv@LybT3MOxKl>bsE&UXZ$Ip z{9E|!I3}3qq<5TpEBgM2Fd>8xLdbXGrlI0`;^k^_vKX`yiK8hnhz`xWLj8>An&8l4 zn}_O;w*6}p{Are(N}1OxZrBzgAG%KuR0{AWJbGaURo-DOsJptshKGb1D{I{j=iZ^r zozZnz)neOLxRDt#E-`FyvUJ!P>M*@HDs|Gu2Vsx?HV%&g83*VHE{p&l?`;C}iAdW| zxa17T0EZpmIbWX{v&QW031oP=IN5E5>)2f*lWM34e4+%OecjJVGfo0Zq(e$-Y-F?p zaw(=+tu;c&jrObH(DP(!or%V}bdZJyX2&LhMov#0o=uR&B58O1b7&We%C~qUwuex0gGl2T&jNgi>uYC~A8BbXz5V8RyAC734N=uB>3aoJ<=& zk$9ZfnkGmQ$G|G1*5ovd%5*6LH>Mr9E(8r5bATBKv`t7qQ>xXWYB3|;SYEa38FRoC zTjx5djD$O|x5J~?I41w=Xq`5sjRw0~zFK2Meg#TzeFuQyOvq9~o-9s6iQM>GVbbeg zhZmh_ikb;+QVb`McnKkd5JJd%5clv{J9`R`c_)1HTUeUMIN+7DUmoNDlaos79eB0_ xUcfE>Rlym|SBVdTJ76(%03n1BLI@$>$1h1y`Axivo}B;y002ovPDHLkV1gu^V%Y!y literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00005.png b/test/snapshots/nanox/test_addr_display_unusual_path_reject_address/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Yj&LwL#RobX?V zbQiII^4uMl|Z~1l7yy12MZ$b&j z?TtJM^{@JVDT&uHZn5nzWh-TPv_J7m;jgq0f(|YbTZHdAM)myZxO-=(=&Jp4l55=A zUQcBF*M05wg}=Y7bG1(&{&siyl(&8#-KTdql}}rLm3hWhy}m5glJN5fpDsOd=_5x% z{HDvZre)46&g0e%{pDoXaPf-VTe-XJSGLU(Jj!tDNp8H)+;exzHoZ2kko_Ba_xXNR zr;WUGZIbufwyah@qN*6%Wc!qrE&9UV%v{IGH{4)eXE1ondwSC@^_ATTjUX{kS3j3^ HP6waunSk|hFqW?7)TH`Jk~9Gerv(6ecqmn7nn8uWB;3b zw{g88mtqOmX|1nQ6UyKSixvS1g}CmE5?ACG-| zpBvCv#x={;%P2FXMyx;J&mSL^`zg=uAmI;8wJYD@< J);T3K0RY{rqSycc literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_unusual_path_reject_path/00000.png b/test/snapshots/nanox/test_addr_display_unusual_path_reject_path/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..6ebf2582dda066ab28d4095a45b5b1a1a814312e GIT binary patch literal 500 zcmV#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000}z` z?&-JIox!g;vLOvry@8CZBkwSL9L1fda<$W}qjL@#qs_kU?{~=(wEhj~N%v4Yw#t`z zR~yORJO{g$pkwXC-;sUA?k!h)E7=}^8hg2Oy=-6BX>YXVT{QKc4euALCYkKJQBqCz zoiPV@Vimd*zr%MTy#N3J000000000000000z&8JPE6>4Z7C4vy0000P)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000waunSk|hFqW?7)TH`Jk~9Gerv(6ecqmn7nn8uWB;3b zw{g88mtqOmX|1nQ6UyKSixvS1g}CmE5?ACG-| zpBvCv#x={;%P2FXMyx;J&mSL^`zg=uAmI;8wJYD@< J);T3K0RY{rqSycc literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display/00002.png b/test/snapshots/stax/test_addr_display/00002.png index f59899e9aa967b23177d83aef0c8c2c9041eab91..d35c043577c03e0f29e3fe1f140c17890a2cb37c 100644 GIT binary patch literal 7806 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 STEIvujUL44ZtZQS=>GwV-CW54 diff --git a/test/snapshots/stax/test_addr_display/00004.png b/test/snapshots/stax/test_addr_display/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..f59899e9aa967b23177d83aef0c8c2c9041eab91 GIT binary patch literal 4615 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_reject/00000.png b/test/snapshots/stax/test_addr_display_reject/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ffd9129898cf04120c107e8397875ec0fdf173d3 GIT binary patch literal 8746 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_reject/00001.png b/test/snapshots/stax/test_addr_display_reject/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..27f08963160773a254539075331f32c71385355e GIT binary patch literal 12851 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 MT|Lhe&V}Xv7j4ZP#{d8T literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_reject/00003.png b/test/snapshots/stax/test_addr_display_reject/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..30b434c51f5be56b80b57118f490c5428212d705 GIT binary patch literal 10937 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00000.png b/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1d78f65f239c1376d014b3c3fec4b364a0aab718 GIT binary patch literal 12803 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00002.png b/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..89fef03daf1f47923d49ff72a90d8b500a7d3b48 GIT binary patch literal 13836 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00003.png b/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..b0eba3f0cd7ecd4a6333e26445f27c0419828895 GIT binary patch literal 6545 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 MT|Lhe&V}Xv7j4ZP#{d8T literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00004.png b/test/snapshots/stax/test_addr_display_unusual_path_reject_address/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..30b434c51f5be56b80b57118f490c5428212d705 GIT binary patch literal 10937 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path_reject_path/00000.png b/test/snapshots/stax/test_addr_display_unusual_path_reject_path/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1d78f65f239c1376d014b3c3fec4b364a0aab718 GIT binary patch literal 12803 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 MT|Lhe&V}Xv7j4ZP#{d8T literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_addr_display_unusual_path_reject_path/00002.png b/test/snapshots/stax/test_addr_display_unusual_path_reject_path/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..30b434c51f5be56b80b57118f490c5428212d705 GIT binary patch literal 10937 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 STEIvujUL44ZtZQS=>GwV-CW54 literal 0 HcmV?d00001 diff --git a/test/test_1to2.py b/test/test_1to2.py index b1d5347..a693b19 100755 --- a/test/test_1to2.py +++ b/test/test_1to2.py @@ -19,6 +19,7 @@ from binascii import hexlify from pathlib import Path from inspect import currentframe +from conftest import ROOT_SCREENSHOT_PATH trusted_input = None @@ -43,12 +44,13 @@ def test_1to2_get_pubkey(backend, firmware, navigator): NavInsID.TAPPABLE_CENTER_TAP, [ NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, NavInsID.WAIT_FOR_HOME_SCREEN - ], "Show", - Path(__file__).parent.resolve(), path) + ], "Show", ROOT_SCREENSHOT_PATH, path) else: - navigator.navigate_until_text_and_compare( - NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Approve", - Path(__file__).parent.resolve(), path) + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Approve", + ROOT_SCREENSHOT_PATH, + path) # ################# GET TRUSTED INPUT ######################### @@ -137,12 +139,13 @@ def test_1to2_hash_input_finalize(backend, firmware, navigator): NavInsID.TAPPABLE_CENTER_TAP, [ NavInsID.USE_CASE_REVIEW_CONFIRM, NavInsID.WAIT_FOR_HOME_SCREEN - ], "Hold", - Path(__file__).parent.resolve(), path) + ], "Hold", ROOT_SCREENSHOT_PATH, path) else: - navigator.navigate_until_text_and_compare( - NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Accept", - Path(__file__).parent.resolve(), path) + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Accept", + ROOT_SCREENSHOT_PATH, + path) # ################# HASH SIGN ######################### diff --git a/test/test_1to2_warning_change.py b/test/test_1to2_warning_change.py index 26747d8..13fcbd8 100755 --- a/test/test_1to2_warning_change.py +++ b/test/test_1to2_warning_change.py @@ -25,6 +25,7 @@ from pathlib import Path from inspect import currentframe from binascii import hexlify +from conftest import ROOT_SCREENSHOT_PATH trusted_input = None @@ -101,7 +102,7 @@ def test_1to2_warning_finalize(backend, firmware, navigator): with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: if firmware.device == "stax": navigator.navigate_and_compare( - Path(__file__).parent.resolve(), + ROOT_SCREENSHOT_PATH, test_case_name=test_name, instructions=[NavInsID.USE_CASE_CHOICE_REJECT], screen_change_after_last_instruction=False) @@ -109,7 +110,7 @@ def test_1to2_warning_finalize(backend, firmware, navigator): navigator.navigate_until_text_and_compare( NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Approve", - Path(__file__).parent.resolve(), + ROOT_SCREENSHOT_PATH, test_name, screen_change_after_last_instruction=False) @@ -135,7 +136,7 @@ def test_1to2_warning_finalize(backend, firmware, navigator): instructions.append(NavInsID.WAIT_FOR_HOME_SCREEN) navigator.navigate_and_compare( - Path(__file__).parent.resolve(), + ROOT_SCREENSHOT_PATH, test_case_name=test_name, instructions=instructions, screen_change_after_last_instruction=False, @@ -148,7 +149,7 @@ def test_1to2_warning_finalize(backend, firmware, navigator): navigator.navigate_until_text_and_compare( NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Accept", - Path(__file__).parent.resolve(), + ROOT_SCREENSHOT_PATH, test, screen_change_after_last_instruction=False) idx += 1 diff --git a/test/test_2to2.py b/test/test_2to2.py index 51519d4..01b8e79 100755 --- a/test/test_2to2.py +++ b/test/test_2to2.py @@ -19,6 +19,7 @@ from pathlib import Path from inspect import currentframe from ragger.navigator import NavInsID, NavIns +from conftest import ROOT_SCREENSHOT_PATH trusted_input_1 = None trusted_input_2 = None @@ -161,12 +162,13 @@ def test_2to2_finalize_1(backend, firmware, navigator): NavInsID.TAPPABLE_CENTER_TAP, [ NavInsID.USE_CASE_REVIEW_CONFIRM, NavInsID.WAIT_FOR_HOME_SCREEN - ], "Hold", - Path(__file__).parent.resolve(), path) + ], "Hold", ROOT_SCREENSHOT_PATH, path) else: - navigator.navigate_until_text_and_compare( - NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Accept", - Path(__file__).parent.resolve(), path) + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Accept", + ROOT_SCREENSHOT_PATH, + path) ################# HASH SIGN N°1 ######################### diff --git a/test/test_show_address.py b/test/test_show_address.py index 6b72b9a..16cf7b8 100644 --- a/test/test_show_address.py +++ b/test/test_show_address.py @@ -1,7 +1,9 @@ from ragger.navigator import NavInsID +from ragger.backend import RaisePolicy from binascii import hexlify from pathlib import Path from inspect import currentframe +from conftest import ROOT_SCREENSHOT_PATH def test_addr_display(backend, firmware, navigator): @@ -16,24 +18,30 @@ def test_addr_display(backend, firmware, navigator): # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode - path = Path(currentframe().f_code.co_name) + test_name = Path(currentframe().f_code.co_name) with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: if firmware.device == "stax": - navigator.navigate_until_text_and_compare( - NavInsID.TAPPABLE_CENTER_TAP, [ + navigator.navigate_and_compare( + ROOT_SCREENSHOT_PATH, + test_name, + [ + NavInsID.TAPPABLE_CENTER_TAP, NavInsID.TAPPABLE_CENTER_TAP, + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_EXIT_QR, NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, NavInsID.WAIT_FOR_HOME_SCREEN - ], "Show", - Path(__file__).parent.resolve(), path) + ], + ) else: - navigator.navigate_until_text_and_compare( - NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Approve", - Path(__file__).parent.resolve(), path) + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Approve", + ROOT_SCREENSHOT_PATH, + test_name) -def test_addr_display_unusual_path(backend, firmware, navigator): +def test_addr_display_reject(backend, firmware, navigator): packets = [ - "058000002b8000002a800000000000000000000001" # BIP32 path len, BIP32 path + "058000002c8000002a800000000000000000000001" # BIP32 path len, BIP32 path ] packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0]) / 2) @@ -43,28 +51,122 @@ def test_addr_display_unusual_path(backend, firmware, navigator): # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode - path = Path(currentframe().f_code.co_name) + test_name = Path(currentframe().f_code.co_name) + backend.raise_policy = RaisePolicy.RAISE_NOTHING with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: if firmware.device == "stax": navigator.navigate_and_compare( - Path(__file__).parent.resolve(), path, [ - NavInsID.USE_CASE_CHOICE_REJECT, - NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, + ROOT_SCREENSHOT_PATH, + test_name, + [ + NavInsID.TAPPABLE_CENTER_TAP, + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CANCEL, NavInsID.WAIT_FOR_HOME_SCREEN - ]) + ], + ) + else: + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Reject", + ROOT_SCREENSHOT_PATH, + test_name) + assert (backend.last_async_response.status == 0x6985) + + +def test_addr_display_unusual_path(backend, firmware, navigator): + packets = [ + "058000002b8000002a800000000000000000000001" # BIP32 path len, BIP32 path + ] + + packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] + + # 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key + # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 + # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + + test_name = Path(currentframe().f_code.co_name) + with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "stax": + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.USE_CASE_CHOICE_REJECT, NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, + NavInsID.WAIT_FOR_HOME_SCREEN + ]) elif firmware.device == "nanos": - navigator.navigate_and_compare( - Path(__file__).parent.resolve(), path, [ - NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, - NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, - NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK - ]) + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK + ]) else: - navigator.navigate_and_compare( - Path(__file__).parent.resolve(), path, [ - NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, - NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, - NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK - ]) + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK + ]) + + +def test_addr_display_unusual_path_reject_path(backend, firmware, navigator): + packets = [ + "058000002b8000002a800000000000000000000001" # BIP32 path len, BIP32 path + ] + + packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] + + # 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key + # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 + # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + + test_name = Path(currentframe().f_code.co_name) + backend.raise_policy = RaisePolicy.RAISE_NOTHING + with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "stax": + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.USE_CASE_CHOICE_CONFIRM, NavInsID.WAIT_FOR_HOME_SCREEN + ]) + else: + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK + ]) + assert (backend.last_async_response.status == 0x6985) + + +def test_addr_display_unusual_path_reject_address(backend, firmware, + navigator): + packets = [ + "058000002b8000002a800000000000000000000001" # BIP32 path len, BIP32 path + ] + + packets[0] = "e0400100" + hexlify(bytes([int(len(packets[0]) / 2) + ])).decode("utf-8") + packets[0] + + # 41 04589ae7c835ce76e23cf8feb32f1adf4a7f2ba0ed2ad70801802b0bcd70e99c1c2c03b4c945b672f5d9dc0e5f9cce42afb893299dbf0fce6f02e8f3de580ac5bf pub key + # 23 5473636f46366d566741416b664e78776e716f5a553936654e3534355247594c376135 addr base58 + # c191668478d204284390538897117f8c66ef8dafd2f3e67c0d83ce4fe4f09e53 chaincode + + test_name = Path(currentframe().f_code.co_name) + backend.raise_policy = RaisePolicy.RAISE_NOTHING + with backend.exchange_async_raw(data=bytearray.fromhex(packets[0])) as r: + if firmware.device == "stax": + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.USE_CASE_CHOICE_REJECT, NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CANCEL, + NavInsID.WAIT_FOR_HOME_SCREEN + ]) + elif firmware.device == "nanos": + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK + ]) + else: + navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, [ + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK, + NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK + ]) + assert (backend.last_async_response.status == 0x6985) diff --git a/test/test_sign_message.py b/test/test_sign_message.py index f392bee..2a2f6a7 100755 --- a/test/test_sign_message.py +++ b/test/test_sign_message.py @@ -21,6 +21,7 @@ from binascii import hexlify from ragger.backend import RaisePolicy from ragger.navigator import NavInsID +from conftest import ROOT_SCREENSHOT_PATH ################# SIGN MESSAGE ######################### @@ -48,12 +49,13 @@ def test_decred_sign_message(backend, firmware, navigator): NavInsID.TAPPABLE_CENTER_TAP, [ NavInsID.USE_CASE_REVIEW_CONFIRM, NavInsID.WAIT_FOR_HOME_SCREEN - ], "Hold", - Path(__file__).parent.resolve(), path) + ], "Hold", ROOT_SCREENSHOT_PATH, path) else: - navigator.navigate_until_text_and_compare( - NavInsID.RIGHT_CLICK, [NavInsID.BOTH_CLICK], "Accept", - Path(__file__).parent.resolve(), path) + navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, + [NavInsID.BOTH_CLICK], + "Accept", + ROOT_SCREENSHOT_PATH, + path) result = backend.last_async_response From f6019b08f227dc6b34dcfeab6619d484a80b9c1d Mon Sep 17 00:00:00 2001 From: Sarah Gliner <105934250+sgliner-ledger@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:47:07 +0100 Subject: [PATCH 40/41] [auto]: add PR template --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..98b720f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +# Checklist + +- [ ] App update process has been followed +- [ ] Target branch is `develop` +- [ ] Application version has been bumped + + From f9ec32ba1ba8550410a393ea1d4a5b545101e4ee Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 13 Mar 2024 14:19:03 +0100 Subject: [PATCH 41/41] [auto] Add manifest --- ledger_app.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ledger_app.toml diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 0000000..8f4c403 --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,4 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos", "nanox", "nanos+"]

@lzWX7nWbuh4}_9 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 literal 15536 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 AuK)l5 diff --git a/test/snapshots/stax/test_1to2_hash_input_finalize/00002.png b/test/snapshots/stax/test_1to2_hash_input_finalize/00002.png index bafc92c05f4621bd9c8782378a40210860e3f8ea..ee463b619fd13d09cf916b998de1d5f07b74bffa 100644 GIT binary patch literal 8724 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 literal 8545 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 literal 9215 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 literal 8484 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00004.png b/test/snapshots/stax/test_1to2_warning_finalize/00004.png index 6ec6d8c7989520d1b6c3c1836ea24f29b2baca83..872040d7208617a5348a017a1136dac548e60c5b 100644 GIT binary patch literal 8203 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 E0Lb}KfdBvi literal 8179 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 OVqs!!Tyf3w(Z2x)D?{x7 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00005.png b/test/snapshots/stax/test_1to2_warning_finalize/00005.png index 2bdbf32eeccd978e8e6dd98a788b0ce213726a96..1457ea6de14e83f066c2618b02c523630a245228 100644 GIT binary patch literal 13331 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 literal 13310 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 yShKV z(Qor(?%OSIto`}+P4cWmEoaF^0(ws*a%_I;Q$sIM7ax6m@IK`CT*oIse5mu9p$k?* z)g@|3svArbnX_&I!p3Z&B=`Mx9M7M>wWPoJcdT^(er4R1p-#6u-HkYP S9Qa=kkBOnh&59dN&;J){f7(X? diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00006.png b/test/snapshots/stax/test_1to2_warning_finalize/00006.png index c06c4a93f280793661ba2300f13418cb73063b19..c3204381cb9e2843d685378af44e2e20407e6def 100644 GIT binary patch literal 8504 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 literal 8484 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 diff --git a/test/snapshots/stax/test_1to2_warning_finalize/00007.png b/test/snapshots/stax/test_1to2_warning_finalize/00007.png index 0150cabca9f0744cc4faff4087c067b93cf7db82..d796da79ee24c2a623319fcc2bbe9f8fca3cc134 100644 GIT binary patch literal 8101 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 PuIB3GajyDIVEVrSgEMzX literal 8078 zcmeHs`8%6y+qG?X9_XNSd)jDg*HA;+QZ0hEYL_BvYt%fos5a(V3{})F8`YMSAgvnO z7;8$2NL5oqiV{Rbq=rx;VkRQ-UftjO{Q=)`e8=s;qr%afb% z>-+b}?hz9c+izlg?N2eWU!IDIiND$<4*sHJ(O4oTCWkP&cI8%B4wuOY9y4ZWxvY>B zehJW_R`vJ3E2gKvWPQE&DbC*bRCU-;A?M{dmj7bYVTe7o8IitrM z@$UENPLJwlmz!d+#;s7ExLD2&mtS0Wsh-#uyFLD7<-@bvqz^p)DE{ey&E=!wdv_WB z=ga>T;eQ7b)~80cfA5MGZUm1#!(y>`=65pTdqrWw3SL)F9&VQZ;OZ2u!kIR4JO&m^ zzT<9vvhI?Zi=|W=+BRX(O)i$a1#|JpZGwspi6?K#SBLq5+f!TE`B)?L*D=?uL^1?C zRB^}W3TG0${f#`u_!PW2fgF9&*Yh~ta*?S!CV8UrLoDXnldof@;>mjIFMka#`5F)^ zaebF+gL*2YQ?3c~acs-Mpnh}b#$&eyUxmtbto`=pv=q+;nL{>GU+2l3 zDQg2e;t*nTCO2L!Xe0#fQk7`%^>}gyES*|!>fvSM|JTQjlH6x|)4pAd|NOa!#GIO% zLZ=4_k82dq77}%TYjv`-8UCp38f3kr-YSu}O&UL4)vg--@MFHxUFj>kR7KZ47S^{( zZ-Lu)aPxnzee-;>@6Y8o2A|nR?u;d0x&0;c>)52(G4@`TULy6FB{+)zVfNdw*EFYU zb`nkfzmB7y5(GcN2;;15d_IjLI*HcqX=cNVjV$*iwxp${`6|{BZxeF~^IL(70okXWp! zsIx~4C?TAc2z@Lq*ip&|ff!%-KqU+l7T5t<*2?W2C{>?;ee98T{mh{~8RJrcNWSs)}-c6uasZ4w_GufGxY zHoi4+rb%_;^^e)v1f`(ed@LG`W(U*@Ho)^*MvuSg`LVLH^6gglbkN4;X5{#(yy@v_ zFMTX8>OsAONF-#y`u&1-D<|c@gcqAr3+DbLu`HNxBkL@RsS9Dlc{AGBZYr!hUkQiX zSYJ0bFK8&g{>E}oQy-!66>3lmk|r6vJCJrkZ6JJ&&(|jD9+OCHaYZ1eKa8+g$@%xP zC;9yFYPy3JEIM1=^#oUa)T5dX8L(ZTsE^LsgEp_GtCASgf$TiH3K~PrGqtXZAQQA( z(#!eJ95aRMH=1lzb$E4#9a9Ff`og*5MAD26|~K9-zo|H!(eA3)yiy^X3g z0n^d^f^i9-A$xtAC5(>2hp()zW{S>1(n5Dm_LAe5d3{5t_QV=lN*RHrbR+Y+SBWip z;D(&(^=hz?>ID77#;`$1kdY>B@K z4sTM|Thfv1bZU_ELU7n32h#ySn4`w}%SwuT_q?`dWt4q)cXvH61on97m*4*uoh?5U zP&dp}p#=EaF&hmo$)+r7$t05(On>2q?^72Sxo(s8q^RW@Hv9j0{E|`w)h&9m?p*%t zU)Ct!GdCEK5fKqlQ5Pgtq+`kSfV+LcL`J-qh3=(^<;NC|G$<50%_2JSKDP?ksiA`jB@HIFY^?Wy<*r3B6Vht6fKatVAfEm}!WPh&V%8{MHw* zT8yxi0u2jh1WE>MlfbMC)jTF)ML_Cfw?snS&LQ7y526#Ex1jGopSSa5<%iF1@7pZT z=fW8pMkTmxGX+$|A%HU&^knU)$tC{6Il*DyIeKSnU)zoCrfV>s-X5zz?)03VI0R0& z){dLUjcazPrXS0?NTMT$ZqGFZ-`pG@zw_Q^mU#2h(S3Ccu5ybj?1ghR{p&WEdZv!; zbdRQI=SgF|R-TH@^)q)Zr4R@&1i8?(4biKS4z*vHOwj%mUuqDie)9iO0E!~bsq3|U z25}$9BrnRQM1!{#tnmyDjIW%4d~cO27am;)N2!|`&k29X>TWlL#ZI#*?DN7|1n6yp?57br=2SqB%m?xmKokx|&U2;)JN$oan2ZFBFe8Y0-BVsn z9PZ2b0-Chv9JU)xaTjs3qDfoqZi^hJPj$;0kAfYGqgEn_A!_bZ1NXreZhh~9l;C6~ z5)-2xrW7*T6F`?MvSy8i77EWBZS->=w~U4mykmasjJtx0tESI>Q$BZ0B6ROlJPeY? z*b=al+WjsK6DpQ<<50J?@$vN6*8p)cxU1QA+%>`NxdrgZ3qiZ(`j(cKUe~AoH>DA% z)60B5zb(_*$!UnxKjP%iGb=1EE+!ga9Hfk>niduo1cRT!GjqXw#@RcsFij>ZkP0j5SU0U?i=-_d}>$2hx7G$A2+o5nm=+zZ3U6~ zHD>y)5yX)>Lik|ek`IbPnDW+j(}~JzY=&c(mzDwv%sD*`sER9L-@B6jIvZ7q)6D7G zA?^8b6w=vd_LzX2(Y~^6pj%s|ay2#YZZg@8Cmt^2Zkt!jHq?GbyPvkl9n(2^Q@dMj z^tJdbjF%j{l5@HFCH9G4Zi^p?3K?=LK`QuyWlF6X$IcQ_( z(GncakPRz|H>XZCzcZ}vx03X)rq^K3%ILbMacOH3w{q>X94uV)@~hR8E}B1AFG>63 z4IYoD)J0AtIc;2bq>-Y9V5p)jm@1}&kU{@jKECcIgI;ODQP+=+jp3=CTJP0)bok*-<{_CL?EF!_a2AqJ3!#~o2b7@IMNLu zLZO&u-yDi2s!|LW{8Rex*XkawD(7hGy7HEj<35Ek0lx7MBk&DHikb)Rm zuyA7|`;jv9@bf)^w!0Z`jDsEJ8WblV5A7!wc}cJ>b;C&nm~IXZpK?wlj*WxyApGb0=H3zb-~#U)>pZik2|r0;H1dBF=S4%?a5%+Q_HBKF`Z8q7$i=M7JsUZ1RJZ zbqH%@B;foP*-$}C*0ku(&{~z$R@a&PtiDBd;CB5j!C#Lw^N2R8i-^V$LJ@HQZLhEC z+{ml~RR6sFcP3*nnyBF^tU44u2RrO`_UPZOn^_ z&_Q_vGvMrh91{PJ_5V-A@$b%gemd>-H(#fgioBW}ke7~$F1w06f*najVum|^VZonQ z#XD?&1<^OCeF>J`7SUomsQdva8g7W}B65CUv?-DXH1T zulSIVC@OGJ(D)%bkX`hS(@@SijJEK`2Zp9^p+4J^KZLE=AD?})GkDGe8tC5dzelZ9 z7t=kJn_j_`fKxT!^eF8=33gxGo#a$;5t5e1JGFvYEOK&oUMnA@2iRt|jLt8s_s`7$ zvxLJzWjM3!w&qoVFp@a7ex>$ez<|eEIi`^K)uWn{n#=KWWl{wKR70f=0wMbZN&zh2 zbFU_pALLe$K;>6DRR9u8k7lPpAPA_3u`jQdi&j_boGPFr zlzW;TJ27ASfY^~WH(4AlDGn%)HsnY@VNI6}6enRlYchnw}k}+1gfXM2OYktM- zF&4hdSArvVauKxPnWrHeuj86e98q0slqky^k|EHhakv|uDU{VJLi1SfD9(2Xsk17T z%cTKBwxQv;6zU3%4Yrta3T1h3pXi4|=FEw&iDYAfZWCL+1n4y2mixF3E>OY}xmV@3 z1d`=fJ^gC6?lLuf=Ez8n`lzr!IQI*)y4tz|cP6UeS*rsRg1>m9cSjmpktlG-FANhS zsj~wNAFYgVUjLT|>dpc29~+7_A5o(VRVh-J347&q=)D{n?7zIo$xyGte$u{2Dr<`` z1AN!k#fP7MY`{eN&k2sOu^J6TZ8btR%UEdKu6u=gyLTx@M8q^vSCP~m3NuXe;W zzuqw^7b4RKd{F4~Kkn*2f2jVn;+=C{1iYQ8R-h(l!09CbNQYI-cMvxlt*S2Iz2(a0 zW6s9Sg$CZUnQAlU`cPD$kz?A`C z-B!Q#5^m42hvOQ0eJs~jsf<8p1{k?QktomO4zteX$Dxr(;&&HyZ+= zQ;@z3Kwg737(x2%-!ycYe1g#Kr zs7DiL7fc*8A!If6^{ePIA-7vIs}ToCU@I&>PQ9EYci(;NKbMKcZYPx1y~O zO&4VNfbGNX1v`T5W%&tUa28K;M;uCK=1j07z}?RbW@b&WrVd9^*o$m-p;8ivihd4( zvCZQ@4VP{m!y7~!_ICh@jua9c^eaHCES$zOxZqo)7VuM^9jlcR2(sTLvkcozHnC$B z-*bBS4$%qtP!L=3qC$0Y^$iTR{L-UG07X*&xxfb^CBQQg=LUnI-EE~3Ci~M4+Blk1 zYnJYTDN!*1#H=9hA0RW|J%lCUaDQS{HZET|Azq@QXla|t;D(&fx`jYwx>wME69V#( zsGAGN6ww{^QaW$@m| zqBIHap0}<@c(vnz%~raBAp&vS4wyJ|1z-<)MaJAbQ(MAgh9^qDpP_{@M>&HRC}r#w=d{V?14mUhb@;(Ui`f2jgE>#f zJzy8yYBvJY2hSj)pAIQrw#^)02zze>29683@KZCOk*r`rXPUcp}in7t49t>7fBh1NOX_m2N=bmsAOV^NxwBb7n=o4=iHS zmUc$0W&Do)2q=IUuu=0kaV9UC7L_0_)20iL`36i$tx&DY4V~a1oWmNt( z$2?bh!|na0#WlUc9mZzIh_N`_5G$V$l4uFAMo6n(J5L2vxpgmwBfX_{zc*UfG^D(u zn0QQ9iu5Odac;zhIU@bAr%tZKj=09isW1zcU^*C;$&btv^-O00QLvn-l;l?L5HiDk zA$#H=I46t0_m=l*npZohgE20wkl%|9(4Tlg7j6rMS2s?8$j-Cf;cwu}_R}3E+fEKQ zo&hk){uM!6p;E0H?qPgjgO0)%M646uvt2O6L{`vDdF3 zBW;uX(&qz%!{u^8Y5~I1ZWJWt4{p;(q?W1Sq1(}cd7^{erbW%;#OTQfn;2Za5|Bvf zB3^3icr*zs8BTPXdeT(P6Jo~3+dN3hr?#~0Y_@thD;-s4*fJn{)-scGthgox({jMu zKd!%tK-@pqIkf~gIGynthkH>O-rje+0r89aJg6!VijfbO_^{wu>Rn2e>VH>O9@Ck^ z5{P2+sh?&#PF~1`1Nk)MTgw|Vk@Wph%Fs6{kC`{tch$jH5=kT=;=sjT(ty&H{Vb(G zYz4AG+OTnu?Y}1K5a(o5oSd9MUOSYaeMrf9PPp9QEvPyp;jOj*ZD9<`_zS}9!C=40 zIKy50=)T7-u2X>nc^9%R(pG~CR<#2oC*jXzd`N?NDw>$iKNFRp;rAc|_iKlI@X6#; zFrHL#fL*NHN3?h0a2-pPi^<{lKLOO2_;llvx|YkWCS7ya zUB6RdrG}|7`ymaKf-&I6Z9i?uzjsQB ce_G!HVKwAnkQ);GpIywv2!5^ns>`GQ0tHp|GfNQv2LE{zW3hu-uu3; z>;C;G_p`cNjJ9ZKXz040`_W57W8HlX4b8`!G=UL&kJd^J4U;9;A5UJqQ7GgH54ylt<%lge853*hWlfE(=CwBuuivrl*AC6jZGI@A5NnNgCrIZHwG}D|656 zP#y+MlcfgZXP#&C_kdMJv=SP5-_)XATT?Lk?32MV^XwA4mUC4VQO63XS{lv+9Pnm# zGpFc*PU+P~0~_t3*IB96wyojk%cg>p5gVL`AX!Iu>r>~NsY5EdFcF>FYu%O`yP#|B zkB@-C_(q3S5TiftDt{r)^=jXXJQ$I(@xbo&BljP;c)p5kctgpRH+W469*cEWceRs; zA)MK(`Loka!Gnl%u=vU=Zlk~ih-kGHr>+sgr)-Ik~cgY`uM~1iu-G*)l zE{fhivpio;B?V@3F3CBQJlV)u)XVxHFyWwooOZIO!IQzK1t$%2Q_<+kito64UUipl zS2`wL34>d}TVOB=VnE*Upv!XoFDV_Aqx-rvuiq+fq-SdWUn^ZI(`4Wn*SzD~ zqg3{QJ52#)u@G=?eT`u7$}->Z&WhCq^~oZ3wNIrmu^>G=+Qz6zvAJ7BmSx~#DeSjV zx#ew(U32ny>nL_&TQFvj`J5X;4N_D4o)fA-mc8|ed@L55J?BUvvl7}yqicfmN)CYG zd0M=7&y-^Ya5xVhmHvL3cMJ_@sS4!7`oQK?RP?*47Z0EC3mHgQudy$v;XN$GQ<6^Zs9oeq>WLJ0vz<|XMbqXj2@+@g-eKQ9+Y~5-O6s4OtekPF)x7zV+mV=Zkl}fqOnZ7*ZEr5l1w)3Ip)knUH*i8ulGz0KI)vfq|7Mp{fMmJjrkzk zoroxpK2{(P;k}%Wpxfxm3ev8ICU~&4-3pNAr^gnKU)M`yLJQCk7Kwld#f>r0eb^$U zN|ko3pf9ok1@f1EEOGSlOA17xQ*Bi)A zXM_`xcN2|93l7Sbmg0iMDQ)Q~DFI*t?@Xhq0a$H9eei2*DT{9Fx4N#~p_aC}i7g!Z zy^Y>5AsBpwnib39?fceD;^ZdnH)Na)?Ug@1hdZ4uJQmBdsTDjvL6JPHs21374vv(DDw4ODt(G#byO*RTZiySVqU3!IExW}wOV*#Y`& z$5$5w68j<-{THZ&GWYQ+g+Z89Yf(5cW|Nh?R@N03ho?1tB6{DcKoMXNN?x(D{ zMt&R==edxY>U6&p8Y<)o*Iov_oghMig)I%eXJVrGT<>G{b zQ(6oYGpVa2bsNvL!)WQi6=_4eioRV2P4x~1gX<-ZYvaNb5bz4WGafW! zqW%Y$IIz@+o+hFnO2>0jfBsx{0~pfV1-CI(se8J}ZD8;G>2}Bq+gHkSA;x|RmHNh; zkb$nJ+UA!V{H4E-0uB9EpbOLC!~Nw~8^Cg-a%8b-;X8d~A;^Q>=AYR5it4UzELDf(1Z}+$uMX!jd%$;bP^W#hG|pwiYV~#P zpJ);_-zx!2#BmejJ{PmHBcU46NB7cflv$~Ad#w|A(GF8i6j3+q^u5^Qs zKVFM$Nc%&Ef)!nz*8lXAz$anw<%-mtD6o{-)YjAh(GGdjkiK-M9>e3y9$49qY&mEGZ=H{$fBbZORTdRO-n6!jR`NNw(V;4t z_%eeF!i?~r7kLn5(~aFXRhf^|byJPho@32@4CoC-OR>Xw{pT~FPGh^C`>>XhS;pn1 zz*5-`7f;yRvZ8aEyHsK0>y#vhp!vvUvRn1iidG(0`dVa*#Z6G7Q!* z`boi4yYyGT2|wa`$O<9p+Ej(M-&9_2Wti>aY2Y^Oc;$C>lBzUl|1e+edxf3&g~Vsf zcmuG`e;R`hYTW7TkxtGvY4IZXpo@%cO-^44gS?Asvi~TvZ|^{`S0s|731%Lo;dxI_ zmL&WLpXfqEzJvjkzOZoN@oc>nb82w`S~1mQfpdkyh&vqepaU=Ooq3YVD8ZD`a)T}k zdk_sa1c1hKXeft6RcG@Dc>EWaV6bNv?N+@21(C~B>Qn6xdrihWMpM}Q_%UY!Qucuh zUb}VoMsl)iR#5QW<`|w>meOWgzsJIY=uTn_SLUd#?d`LIFgj>`#(d;E89Bn zC-8zBYfblay1u(}>BysaY$J=sYL4-(e0y@hm)#u0?vHFpeORvbGlhLI976x<~yPSZIKUxJQM=4F-)hAL^}V<6XA{_^i?23H}V{RK4Pb zDAUWY%b`M_|ED9N9OPJb{eU)C>{&cKy{-8abjAc$Of6rN>UVG4yQVJE( zK@`oUY2PGidF7wD?3_qe2x?#&*mt4u5Ihn7Jz;9`5Kjop+y+P!{zVMjIyRrvbHH``inT|Ibh!5gl(*#aBv2F>6EKTQGLEIDx$0*~ z&OOs6DbD-j58k||Lv(mIB=7|pBRVT%5oJBjy1y9nmXcoj(p4K;_GU;9%VsaaSx*KJ zNLEW(!`Ftjcq{6Roa^p$ku>@1^Ek{{JN-HsLu&ML8!o&Ws;(tHR&Uf4gn3~cK}wH&t$=;vUj4!l>lBB1q1mOyViiC!3fQWs1*ty16Y=UOAhpvW_S7&~3re z^&=^5^DB9!o`mk3PNEN~zP_f;$%i$LTDxMj7RINuyZ7iuoD)sh5um}Zj@c(wc@fC$abqKoHd zX3Wzvel*?peL>&Qs)#@!y!p`ERSu{Jq!>zZ4_)gavaq+zG9i2Mh9hwR)kHm%nhJKc zY~mor=M$U>W)@$AOKwXJNB9F-`lT3ziR@+}Q1GL@!&hE$kc8MWRsuwMb@Rl;#L~`R z=IaO>F}%xZLk~(9?`yG5c#4!=**KGa`x&L z2EMn<+Bvx@)!m78JzZ&sbjk{WFj0r{jjy`@QSKqq7`G$f+DpWW5{Fu9MwPx=(6TSJ z)w2Ea{EO3Vyx(Ybvl%!{_suHuZ@*{HDZ`$;QoDmUXZ)|+`#NiT$8%r1=WAAn{{Pk9 zDPqY1pUSsS47J{))(l(*ZTi0a{Fmkb2DQ10`K5Ce}FY4&Yn&48Z51f(T6 zE5RS{%W4fK6N$v^lATy)Y-}vcdJnf(TY61XQ1wN?{4Bjn;;2;>b9eGldO%OHG(_eB zy{Y-o9YF2z_-3V~)0s_ms|%=J0%;1q$M?>F+()C25s_^G<*|%XudbfUdhQ#m> zM;&=IPFWa8M0%&PwVB5Q{D^?qWgHB2GAAPGhXt`%%w#glw)?=ExFQktw^SX_co#n& zR63V;VgGRkpyN`(?|{nVAiZngQLBwAbFtubg;B6w-*UJv#CSSfW>)#=PFjG_1;v<3 zG!7Q_?1H!9l-Qvbhy}^ZAI}ucPE_8~ZQ+Uv%K6C2ii!y?mmY!djYz3Pgi-+HUw z(db0SY%PGkwKS_cWt_zut)tO##Qu}I+MHy_Rmh_YD~dEYi*uVBeT=Dd%oMA?17Txi zLhigz*)}{C3qIwQk_5RG0!5*RGHJxi0LW|yl{E{sM#XH5pc1C|V zIXSH;RB_Z-*0T>Rq>7B;L}+>9KO!3*^+hHp$Ms%n7@htNkq@Xl%Y|L&Euh_9Zo`1! zTlgnuqHQLQ$`wf!X?i*H<$@7FRSQ3ojKK_W*xFf1;KBk^g(@BJBbqXaV)P~o*51$2 zCZdmlKp;+(NAc5Nqu05A?RU9Ir>ZX!=b^UH|LYb9%<^VQPWDWFqgX)b;l zkXQG}4S<#VajwHQ+OacTb`&F;B);Hl4ojSUJYEl61+;1W()J$Aaq7kzjSqs)5UO z&g)vUIa+^AA<)l|w?4ePj*Sa=rsUqT?AvG2f2r+ z1Q+0FgNqy?5YFoTYj75@pL9;m7Xg}S8AD-n85q(lBPXf#7!vYUeVc>_od|{Rhd(I2 zH7SuavCF)G!yQy6AY@mV0KQWLs`Y9jhK^o@!MLLq4+;u_ObEGNhBH0tfg$@;#y6jv zgyClvsF=Y-!Lwtwcx%qCk71>X?znRRAVFSr7R@uU7XZ~yA(P1@5=l@|7pc#DI1CTm zknrQ}i`+fZyZ+(gYtDjq#*06!h(eRo($dn?0cp>kdYhd0Ihd%o<$6ua(#4`JHJAOm zjzgwumyU}=4NfIly#?}HBn6Z@=51$_thYZ1iEE}FjX_}B0ypXSMB8)B;cuU=H8}aM zjxWsbvv5fY_px=7YkzM}y_RmSeG&#s-tCkAJ!VfAFP$J9S$keK2|xWJOm|eXa9?fz z+~z7IDK_bZ+rVQUZg2BOy*wwso5c?xXFKmtO@>dZJM53!w4%e%@KB*tQCver-3ma@ z0`nx2bLKS#QQ*zwL6e*}CcoV;o^@`I+l6Hkoo1X<$8hGuU00df3nzK*1Mt6~Iu?lC z-nKz=wE5&sk&l;^eTyUKu^UO#yu-vqC^a7_syY z7k0>zeAAKWV^E3_L%#0Bs_SxCnr+AyJ>TKZfA@9i)S3o#lv|Rp*s29w0&BRsxc^vl ID)g8C0X{)O-T(jq literal 7702 zcmeI1X;f2Zx5p6`t0J^GpvX{50g(tufyitJoR|a}W)c*cCm8|)8LC)uC`4sa0>m=P z7$l4dNl=P0&=4VzKuMsKA%-vrA;u&G?%`ec-gQ6Ub>Fx5!<$c8C+p{ncqu9Ec%-DH{QNUz;EJtBcfFF54)4+r-~M>BWQn%~uj`*u z3HeBH-&vw@aqqH*>)z^J-nR>%8~moxddF}3%f-F&t*d3x$@fO1Aslg6+McXeA?BS(Vq9^{MieSjd& zYFD2PZ1mxEDF1Yi()zPisr$q7qpB)-^slK;|F|HMBD#X0wqZn7(1UWD6%-ZcUQ<7M zS${w3DQPzw;b=C{BECkv=YpKPuh5p$g*& z%Hl=9_VYLy&J{LnbpLgG-J0dbLw*7bhr{XU=#V!lfAE88`8j)zz>!=qTAc3&0X{&k z7lt?MktqJVhSUmX4$QiA|ahonulm{R@o+8M&2v%0Cf%`m>z) zqI8j1fpWqzu@$3ok7pOc+YDX4sFvuUp27y^*52$WG&3`E_FO+E%Qs~YPZ_%n{~Wl= z{Ik}i+SSFQ<1=iYAT1lmchO@Q4=t=?}eThn8NrZhl)j(dbjZl!`??j6JJeCg0nKH!S zMi8KRG}YRY42GK}>LLuP4q z?#M%D|3byirjrlCd3AMK7#aiu2)yswV`xyL4@#90Z)OsqDHrxAPa~W|3>cRT>E?+gF@Q3O4=76^Bn=N(ond4b${P zZ}P?yxvlgB!VnpN{{1?M(#0b-K|}mL}Z3w9qBGlGn2j~P^naA zIAJ_Cby+_K^%w0{!8cWCyAG;)Z~i@stY$$JpPzX>aLbLnsCPuXxk(w1wZ<|IJ8*s9 zlEn`4yU9-L5k(tg4>Xwaz{0!3&Q-}YgjNU%E7@wv8j*? z1Og5o#$+;mjW{AvvT4^i=6niF;Vow9fOA}ypZ=L=$($}SZL<5buI{n{_(C|s4akh5 zQi>?sxxBR07}{S{R5bI1BNVe(tfVe`aCw_m;wtlPf#s|Ld9wS}YxNJKw?b zz8e@Akjv%S`~q%eKOhL2NMo1yZ4WX2_GVdGS@Bj}&b8AIu30==_viBG1UUvysUOv% zly1mKb#-}+`W6svW)-#l*a0LvsyS|t@9yqi*FHE^*PB6JX4&dL!mBl?t3NR@tsWFC z?*Q`bV7D09JD1SNR$N9cF7ijK|#!Gi3r%L>SIKYC8lI4RX)!13-gb+#%{v&hqihKS3brzbNztAb^_0_Sl-1H z{YKf*obz2Pu`m5n_V@_7-;}z0qqkB?;*>#;wb8V_Odfv_4a?B0>jgAqHGBN3k)1qq zp$VEhV?z0n|K^FFUFNWBefdd1G&#P-(h;}-dIrl_yU7t}Ad3<;5PM)ce(Bv1p<~9R zRc3BT0G=ZN{h`Gi&9_Y?%zNKq@WbWr(_vKp$y;{Y=?^Sc_k@kyb>J6j6vs8?mfrEB zST+~)iR`5=grlp@5kRABYfofh@|B0cV>SNXmF!PpnjiyKmS0hmUVTx~cI-!>DediKk<|Fq=jPCC+A0Q>nVz*z* zrg9(2D{UR`C98*s(+{;u{iim04-f}ohx|yqrY;X$P^9Qdqdb(NW8u@kHyW zSF~4`Fv1x|;c28`q0i82?wFB-XqP7PfcG~Zfkq$MIii_#EO;PSh;X5+>7k^dgjV($LJ1G!Lm~L^5}0cYB0bk(j0diW#-%DMCeW zfE5OpHU$KHCrKTr}~o-W46!VJ1{t!jf#|o~Kap`x{z7nNTy! z<0Ae8Th7~+@n6}Xh4O->Wfw<|@7mRn;9wwM)E5zo*~4LyLDuTGTQ&v$G{V$cj6ULf zoUWfBlVY}TT9&-9U{=INE{atf=C2o_jG7+CSedFwA z11rl;k1d_;cE%{~JV%KUTAQ8=#6hadO?hXT-DUMxb9%3ZHZC|wXZh^PH}ccNNe|0k z)GZ7rs!pXkO;aeDAv><4>U94fr1r=`4_^d z@0rO-RX+6)&qMHFz|~~OMmyf`A=V5yQhI8IGO^eSe!`=MHSc-msH$P! zCCOLAaBtIvxw*O7UmBkP{tQD?nAPS+;9LzM5ae0^7-Jn1J8dbOg^ykEhT%E2U^4S^DJyvKu&lvOQvS2p zT%Ze>w>)}fdL@}cVZ+G*jR6iYcrXX<01R24#cIDOP*gvV?cK|j2T{v7$N0xpZ)4gP zw_Q_P0O&|#Zda&L1dhp%y5HrHG~~5FG#zLeFTAw7i6d+OypMSdj>Bx59O7wQ{`r)(SXX z-hrvF3d&#Zec-qNNP*UtdxdJ~kz?ZdHFoOdSgV&&;PWWA;KP%pF0W~T>T0JP zNRb}_YgxNVgif}0=6OEZx7g&7A?Y1><5IMCsUmPCFt$!aC*^c-DV1408I>bhEJPJ( z;LthRL7d&#u+UfUc+{Kvgs7@i`E?G>Uqn1JN0jg&871rfPmGqYiUO0vb)&! zk_ma{`8PJTSi!>gCXCIi^5r*G2#=^LK!jZ?^Xi%V7VJLvQ_st|9+>r0)1#GI7&z0N zKBM79=UoWSNF(u5VTUI>^YI*`z~qUKB*^9-mSEGIPlVfML}LP>>3@~ceqT)-OZ2v| zQX*m9bqIhcEq|E#Sd~Ib=slf4_jyU{*s%3Eb)cX#wDICDc5g|yhz!NsDaVkZ;7r%y z7X#%NaA}E@dJ_yT_P{xYl^|ZJ42yi}SNW@|fOotoNpP9>zO&8<&%%bnuy}xV0Y>S3 zD6ivM=huj*Kqbp$L|!}$2J^mIrQcn_BG=UkQi^HdDtcYrLUJp=3!q%Xniprk)gX+6 za<)+E>6cDZ>|>+tbc5XXQHtY@;qPSoEDP2(_e3cpLprhO<#hzeTW#j0tHCOp#?MmjN@84y1}*BMTuOT z5q!uQ0s+X?(CGa*GStb*Nz?g^E@o+W2VG+RHr_p15P67IE`)lWlhB&cK4 z`3g@-K5!KPq^Ts}UMsk~eK799>dg}CaQ{L~-2^(v<@Le#iKQv@7MU0CK>-*JYHL%` z2a#onq#FPb5D0+&>O?eEPmT9>HOy-PJuH9MEwfOrZ)_5V>$(}{r9|^$t)&?^NIVLK z;`rh=LKA4k*1qexx6keJ33M-S0Rf7OwXUzL0}Z?iX$~?4M3s^D(hne&_L&PmFHL(JsPxgH)E(^?QN=1k$$8-?T{3NWVV3U}!RsL>Mn=@DlEV7KX(P@vH5d z&fy#zg6M@K#cx+~X)}!Qyr%mP%0Jz9do2H@1)#j#K6Zq_p(BpzHuT3+2d5U3b|qyY zY|ZgU$Y@s-V6L~ROgJNW;ger~abRb9EB||PRL6u>QQO3lyL&3)(ISB04nK7@OmDGM z@ew}VSaciee-5&`V-}pjjLUQmfg?T#j$t-+xoh_){pNtRWz7htVEF;MfHC+AnAitV6edBGf#Ts!Pma!E#5#enK4mSlb3a|lQJO|XCzSfx% z@h7GynojGX$227a-Ql_g!15Y}x!o)C-eJjlab-?eydHJTc6d#gp6!S-pzrw*Vtx_7 zuE&0aDVaaRu3K1zvyI{&Xxlb2!|ZiE4D-6xVK3L!JK}I|kHO)C)js|#@Acg{SpvjT7> zK%g?nTNh}*A#<}!ENGcGgysX@lfc9S2xUP<47jb&^fDFzMU`i+0LW4xFy^(o zsq1PpCnE%kjwR={mfVK``V{b%QYZE`2w$&KFNG*vCgG-WPXJ^zOAwN0-))#juI1~D z0*<#-bPW3yJlMg>sm6-&*b-njzC%?mE7Ul%Vb8_W{O>Ggnl}w_M_D`5jNEEiQ&coi zVs@BJ0L{li_k)TCMhp^Xo)NZ8%W7OpX+}s!)JC4Qv*)3#S6?2ODs?pkwu)a%B{6m) z|p@+3N+3hXa^0nYz@m3CLX37!XBq$6hD=-UPlj{ zX!8SAv!XI2v0ZA-Fkw!P~n(GyH+N2i?CE=Hc@RlE$CLv-%Lbr=VX#@m2jw1o;Z<0c+j_Z`;f z?e;;N?)At-qZ8V%024S@JG8X&l^sJr+WcsWy>tjBbNne!y}C_pFwc8_ADAC(T9i&E z;zt4;zC|vV03yD~oYKYzYq4>@{PHTvRC}KRw!C6&{)1LkmrMuOak7fdLd0q)6x}MS2a85QHc= z1_(u(As}K15CTGkh=F(y&bRK5yY5+~H$YT)bXerlG;La5bOf3i`O*Fe|XdPKdBN3mKJ5-ps%voGCNHR!D zkap%0PfT`BDwTdJ?ZqX2G#Mmqz_pRS!}tyfJ$d4B%~H==gOT~#;|eux$xJ+X{8++Y z%-*{M5U96m~5 z-QGJtvm28GksgZ4U19%dc8(oiKS_%?<5>=xA3D`n4gp0eM>bW9Bw%^Z$oa6BnjYgw zw>z>jZTWLZ!$1dFh4a3n`wp#Z;+R?DJxkp{m!9By5XPaz9-3q^7N>9h zmsG-hN7KwQr&1g68-OAbHPY)bBhc^_lM?iUB#$j|_R+>-fo}AZC?=l*=p6OO6}bX- z=d<@6G;g$mcwMUPL%l>3=J_J&D#J%d8(n%~$sR{m#y&cIG;IZab${4+z0wv~?zmK0 zsV%5jW4>hXQ$HMJA-*F}Q{Z8x0POLgYOO{jVPt?`6cl#t-)hl+)LsAo@PFV8{O^tW zjlOpJRr;_;Yp(Hp04mOO266Hm)Xychd-su-ZMkQ;3Uau3RbpPUufMH;{6zl!Ip`P6 zsv7>BeYH{37kwc=2-ADfSWs?1#lz(jmnh4yRmq)=$3&GU`%O5sItWd&<8W0+wy#>@ zl%8_Ynv;@zdICMwZoNGfWfXagjYoIo{CQO#_z5}dl^{NAr{PZhVgd ziAg_n;)D0Nn929HvQNnETR2IdqD6}83HBvYc6w&}uL*J(H7Wf`LB6>r`mQrb*zuFm z?Jp6=Xf(oLvJH<6PWKrl zlNG>Qvwz?i`oMew8fp;Vg7z zqLk!9=UzWqZlTJ4{}9}NNA2RdhoW{|qTi>Z9jZlm6O*{JzhfOEtWLxT(G2bV13F}{=E1r3eJY3k=c#2J1&n7xA#(RlYW;!qGtMUk$Hhsy2 zHT+R-dx{I#8Ku>vRf#Pz$TPxVnaWC`?%)vt7V>#Sc~T%38;9eS;Q>ugNy;pMN69P>DNITG>EEkZ{!4^OW3 zbhFOGySL6h_qJo%2(tC|_F4(&#H%5P*Lwp|!~{C0Ax39lE7%^29QJ62T2H;BV^nX8 zr6+w&`AiP6t%uZ3u2CqIN&2=Pv{q<~GO42Ua@ZqO6TBW@afur@$~e#=DCXgJqSW;D z!Ti|G%?NEqb1)eB_<+UA&?01ZJ1A65{6)u{<>F3H7};pB$;nIU7T|^yQ#v4qg0F+u znOJRuf=c?{9Qdyfn~bDs_fyHi;7oPYXg}T!EY)_ib77O#i*Mg%LFz&xL3h3w+Cw8U z3F{mXejzqPVUuO9yNl1uNS?g7rtNCXv)7A3N&>vNpdJ|Vc#-)`@a>x)3wBPV~mGlM6)vXGQ6{|0SGZL3yOKMz8ojAP?8Sw#sjT1Z#E?RKnwT6uS? zYLDE=Y8bE!4~c@RiU5CjzH#2{C-aH-dQM56gOOqN>KGmFJG_a`J+Qng=qVS)#z%}` z9m&9wKJ3H9vysb-ht@{Qn2}`(bueZvDd4Ww2rYujnr??R+K;&4TG!2|&E0!op0>-_ zl|1|l?f#`LC?mJJu=b*uXAkVIIi7JKV|H0;dj)J4Zo-38!nb%%`H=BTWxwvW{I)R3 zNjv$$=ef6!zEX5>4-D|GEJ3FMQky$rCnuU?EXkj;IAZs~Ey5k}ZoA#&!ETV|5QUzs ztlzD^(2r>Q$sYVC$hh$p~ zuwA!dmW;HpLEDuv+5*D{0b0pDOCZ4=^`(Z(yp#(vdbPS!oK|raU|W% z6gqRUhZJC&YlBrm50_~RkS*%ydw%iukxp$+wMp!O#pTgiRZZ*081?yAp6t{J^rU0K zXC{_83xhDy+K`}}%|c=?r=obG&FSH84cPsZ#7T!W`ksSULeYawW{;dX>AP~4ObwD? zO8K(!9m8z?>eaMiK6dabG|&Cd>47ufO5LCX5$NHTx|o>h!oEEgtC&Ec3AoIt=oM2Y zUo>HC??T|8#<4yrowXf{elD#TEj3C6hFyv&yU*&QTZSZE zvt*KPF9m$KHFkg?|M4;pqke(9lt@MtZ!&@CKoR9LmS_?7nrP3AQVl7#_PMsnqM--@ z7uBJ0WBtuH#^(t1xk88rBMp8g6n9#eo~e4~-{@W#D3X(*^Fvn@@l z@?u$ay;nr|-V4hmIC%3GJYeg6o5c zs1*XP>QsB@=ktu(G(`<}{3=y|%e8=H+L4_-5}D`%}&CZ`?$c+ zA_67-P5FMkHg*#=>k;#G_JjO_oO^?LHD=%Svle)SBJQvuzmS=k!&tuBL& zq?HX}Bu`7`V1?GXC+@b$iV%tXiS|l|r2BU~^bg3Pnu5&jZ$mwpl$du4Wzm#SdaV|( zarR4fA|;@yVcM6>iFT-8_g5&U&?3-J7WO^#N&DKjCnkN|`|oX}DyvNR^OGvBdlz)< zHzAUlQE%y(2GamUO7Z#dl9r?#${xXK7-_y+G`hSr5^FL=l9PuEwa5PWhIN`v9OLH@ z!CK?YQABXJ1%za?10*NR^)-cC@qZ%UcK_Oau|S_ztE&C&sdHC}BOhD^INwe+@XaoH z-iRwj?>4hlZ##+9jo3%P8J1B96?+dAAH5Q>i0^gVeqqJN%zKk$w{|-kgLx3=#HiU_ zv1`9m7k#?3aUfT*%VPJ}zHOE+9ENC~Tn!6ZP?3kL&hbPn)AtC3%!8Jc!zmZQ8PRMg zV&&slB2Y9WaX#&92lsNlV+$(Dgp=@1LO=rWmgwKl6X@GT$s5Ob?yiNyYKQNHp&0EM z=$;`{$5oi-HD_$v>o|N`Z4BBNH|#nrcDj4vk|q2_G)bNXS8P%U-E`k#!E8Rm`r_f` zsQBLUS73r(31L^R80|QL|I}$Ox@;sA8d$-k_p4D!%U>Yh&Hn__GLR|6j?7B!c0#C? zD_C*--CBXI50S@8MCypW@bW2d*2dF!VvnPd4fr`db&sY1n}vz(QL(Z)R!?oiS+1iR zqp|Yl^evAC1`nz#42kRBS$c_{AU|vW;F88xI}YSh@nEo2=3uvp-DEAFd_Gfk;b;wu%sfV?I+qBu|; zIqTP9SAUr^C~#}6+nwzYzsZG8w^0yP6W+~G;f9G>KlRXC`!*PI(_5IYW_&4-Rg{|BV?e?mw9Bw_ylcmEq0*w!E&1Hjd_Sx^F#6qHgV%t54IN zj|7$vTH9nGxMzQXCSVqSw<&(-+X{#b$w@4*Vl)z`_Qxw&a;kZ35{w*5|0P z{F;*3FFm{dvhImS`%M4Qd$;N#Q(h{7lE9Z;pQAjoenQUR)oWk(hf3LOJo#5r?M@pL zF83Y1aJw2ZP^xmPDPc9MHb;5RPe{(W{Hm`zuPXiTxVrV^>vE3r>t6)roI~bIA=fr} zjDB*gS8bT#<(#q2Pk)O-O45NH2=}j@mOp3hjBM)===+nQe{{@;(BG~2j(y)d+IyH% zP9(eZ9z#8;tU=g+$4asFRS2NyLTrBk7-VQ%*iRjaTl|QakLqC^9K`OdgJLx$Gf|ZF z2yN{S^sy3xr*=@5jD`6Js6w8{13b9}hokMUN1$QLp1;g_?oHAYnH+Hy7X5VJ)W+)@ zp8$CLDDN!S9PHRB;lZZvP5|Qf!gLkeKWXyglz4HP8BV&22KqDoQTESoygefo00-Ff zMR?q7|IxE<<@QiSu@paN^mj$B#GNS8B5x@*sz;KaQ>9;tcbXcW5}L?7n5Sa^d`_9z ze@({#Bt$EvM-l%Mgh%*U37c41ORfV;5Gr*!1>yfV*_b`C`n1v;QMRs0BQ#FeN@#K= z(ju7Vo_5MwLOM6S2;W5>xa7Or;=Y7?9?zDk;eB8m!CX-HJbq^C9vLU)nCn5^=??M3 zZsy&sd}J+blGz}{tnD|N4GuurGkP0#q7GI<$`-?SE*~47%$D^Dv4;Z4d3mXOJ*p=T z$lh*$(M zz>E!Re;xvJG%?FVtdl(C>|+&#s*hS2iHdMxlFr}ClJO1GktF>=+Uo56EgGx3hGF7Hy4o{muCzkPHjKk1U%YfouAFFUI8F-x9rk%S{L{v#1GI!J@lM zQOd7dX5QtWyUI@6OkDRZdf)=pGOHYf%>qo`+Mdt1>ur2Vj(Ie^Dko{#T z`TODU!dOxQP2AOXeXs9dnAV$K-GZGmBhlZg@nw(4$(ofzV4Kq}=gr1-UXep;bkx_e zf1P17be<3K&sgmMS8Xy60{D5G<NwB;07uRDD4u$a=(JM7DKP>%0}B-gh0(?bSF`+%MLMdJU1HDxqUUCv3a_o z+a4wy~Fy%-p3f-%~qrQJ2LYR&IZP{~FuvR1#@2AO}J=&r~ENC+`i zL;z6gK5>GVS?J5%)iFgmwoYP12{RFB#M3bBIbCz_Ax_2z~_jRG#7=VO@V%l z(Qu|LiG+5+^xiEI5v?M&ybsRn2ji|tW&)l%=-OoF2zX;tD!0#Dq09?d5+&=JTi7*#0SVlt!kO7N*$u?sQE27A)W#L~GG z;fRTMPA@(pV8SMF#ZdoZ!Xf=>D%BaPz>mL*nK1794Z8^lF>-iG-K-qhuQW82{?i#Dki#F@bl)OPrF38Pn;`!I3 z+d2z=>VTNkZfC>)g-&<-q5FDx@ly2Ui5E|Fd-K_-OY4m2P%Y|e*kz}g=2^e>aHz{E zy}cCugt+FL-%^+9UD0W;zzHgxOLI~e%=)L_JX{vq<(};~5(@^S^BnR6!C}7c4ek{X zwz4E!CymclqgiR+;6wb=JcsYqb2J2)MwU^*flo=&gdP7kNT+91KWD+ z*Y<K(H1@5dpC{X)acT&zE;cDx(e6vJ$ul&f?foHmj>~Hh^ zTCX9Mu>w4nuH#BYjl<$yWqvM4qAs-5{0#=KN6{*$YSYXPaf2td{S2Iq=dp%)M`e@L zjiv+*WrvQ+$CrWjP2igW@?Oa8sym{6N9XTIYxsXx>oXDou*tbw`q%t}B>t&>&;FLq zX4sXUD0R?BtbQ>?J`aDFzyX>Y{M(NIV1wzu#mkLPD2Rf}#$q0whZi^6S(qq}NR(S%(C?rMLDuC*7b&<(D}iB830H_=;Hip&AP5pz^gG+o9_Qo==$%{F&OEBzF^ z#T-6(v?u3PGbzBocU-kzn+;jH3h11U(bmjCbph}Ac@JwEr@Bx**ciuM1I7-!7W8do z?3UFqI_E!Rc7zxeImt++JtAJ|xB*~`c;8Hz2*f$p9q9i#;tT}~37+u$r7f?xb_WHi zSU=L^L+KQ~EyLX+C!1N1aAp#Bq9g{Jbt~_jGF}XV;eP*_Bl?xXJoPe`wjb6{Q~Tur zBm{e)erMCYr#=1?cLfc@VQJ9h6V3&}ZInf;KHm;s*lyOKT)**5Vo|W~GUg%;hqrB> z%UMcp3}NwbvQf>wzF{{NOz<^~mU+q8Pvw_hIuPWiLGQRA^~=t)V$Ya;UQS6?!spGh z+-J8U+w|LvA=nLjy(x)tKhxL27$R+be?~rCGsE9C7w--p=d19CNrIGfyU z%E%aW%XPQSo&B@3c0?j`lS!oQ#^@1o#3U3-VkRK!o~@{fl}k^1Nt7bBelHaeH#3%G z%;v@*ahC12$AFfD&m_BSh8uIyX)jq0v%VhLuO!E7%W@9d8``2-Cv1>ES=N9nhX{kjeXECo2Jvo~DgAsrM_j z5j7!#Y#SUVwtIiJ*j{2T^cPpUqyu_*F8+lCwkhs|MQrJgN8`}t^=H?t?iFhi=n8o^ zfj$1*&z0@i9}LEHY|U(C9i+DZ)$V&6Kz`*^{GdO@ZyT2*HlNnx8+nt0i0g6yW_`bl z+JXX|j^2gn;=DtIiP~gd$P2(o7JN6L4x88Nd{E*Y4s4wEm4@PCt1-HXlW7P0ZBp+6 zIQvDsU22)n{`c@cpC3@|&tVGJ00bIgT%ou;I_cW1g!jz``Uh_OBDz<0{+P1IdC@F7 zeacMPsCuo+?kowDC$n6KT71z7`)okUWHfkb(kHi@Bi;f%FTd8=PPB=Y@Uw%W&CSh= zfhPgTk8h#wL|rLrn6B-Ctw!~XP(ml_cJD}e^{73JNR*NfOmNm6SkKDWz?fzD z?B3|6^>_9}vb3S<$YIy!Z!A`W15Tn6cxdgJdaY6qmZRRCKQ=n+%FJ=$&|Q_*Ad$pq zc^mMcZ7v`@Zoh&z;(Q|4X$#a;AfUm68=mOs#NHr7OM0lIMi7ZiN|sNGcF#p-E~n@7 zYBwFE@)-)U?Ou^%8Z#fZ{VTRr^5E@V{I$d42ImuPYNeqYhE9ycg5>mK*~S?kL|>Q- zhj_AIn3K(#<2f-z z+9&Jg0qQzK;m2-fJ$QT$1Bp8(#=oIjm=qJ{jB^DmyC3_`;D>ibUL|<@73-~ zS&cy3y!bULOfL;Klrea2x}L8O++V%_n@;qX$Swy+z&TZ&4*Fw(A_;2HW%=6^hln?Gzo^q(q`|K)p&fgi_mO8SG{3|eD=uRTC!CgxWgjGPny0}@pfR{#J2 literal 8545 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 H&@6SYv%)Dpx*fk`X6sWp?+ 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00000.png b/test/snapshots/stax/test_2to2_finalize_1/00000.png index 7957045a99f448f98c0daa68ef0592d118726904..f3c2cd88fd4d08fe8c4882caecee2d801038c85e 100644 GIT binary patch literal 8201 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 literal 8176 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 TV-DWr%Q!o^ovl9;^viz$-cC%N diff --git a/test/snapshots/stax/test_2to2_finalize_1/00001.png b/test/snapshots/stax/test_2to2_finalize_1/00001.png index 44ce6e007eff1c3858827a8373b313f02200ef53..d696375426668d2ca37b9c315ced79c70c713860 100644 GIT binary patch literal 15593 zcmd_RcQ~7G+&8SWR9iZ9*&Rw-L9N({SP?{cuKu2JJpa7U`^SAe_j@15d-;Pyu3Y0B-}AH1H+L82xTck-bb;79wk z^WKxsUuK>zKYe?z#Pi5gz%L%EggQ^ic~*KOtUtUq<3w3U`Ca|JNme&^$#QwMAo6a$ z;o%(wdmrBw5dZ#X;=7OYsqY2xxgP@awVf*FOTOy7>rzA=zq25EPu+q44^J3JVI6mw z85$Zo68Etf)6)uzo)D^~y;xvtX&C!r@>P-l?b*9tK_mRNMEGZN>OtQg{nvQ@|Liv0 zNhSWI`zFbm*kU|WIvlm1kp|k(P<@%WW|w$52({2UAHE+Y=0nTzG?fzQ)Cx?v+kMd_ zKF4!PX~SH@yvz}cqb=my>|U2_mje6H<-Wxot`1rkC3zEdL zoIS=+CVEQv2nRzHUQEEZ?Fn5g$^6D1 zbbb!!_r7HOHC|J@>e2EyGhAxhSz8_awVzk+j`G?mug*c=<#=Mq*_?Y+Xm^4E`MF%& z)J2hJO6onu<-e)y5V0Z4xvQ&+yHL5}Uf}K-NvTWcs6Fmd%SBltn}ye4?}%pxpN+V_ zl)%U}jxJiju26XUO`r1~-;bm8eUVQ}vMnnR*4bP0lZej7jYpfGvigkYHxs*i%jNs{ z()kNhQ|_o%;15N8ai9C6FPJ_@yb%6Ro|l5+n#ZHh3S3T&iB^Mvj>o^$)y~hmh%*6O z^#&6X-!G|27@EZEcd|UcxZBF#H2HY*-htTYJ&Su`y~P?A_|e&Mu_^fsNK=+sT9Ky& z9%lFQGa~=}G~T)@$bcpLd7H;8yna69%$~(NKv5g^mA-n>*Tz`qwq3hnx9RhMVYOYm z+jd@0ctlCPV`qX-7d}%MKX>#$THo4M_(&xRdk`vEk`=8I3Sn>w%lax&f970P_!YA{ zy=$Ey)Xku&FX#CWzCpUTFlET4z#y;3xe8b>aJU)VCzn$f&va`jk(a{^M;=arODEt+ z-86aZop?E1QMAYWo9@(h_kfR_q%dtML6l^-1`*ZxOlv8+?*7et4oV9F_@573^YW?# z-I`4IV(qJ*TVo~*-8$|skD8r^s3K%SQ0hX~%y(Lk;T{$#IZ0%6&wze26 zE4E}r#B?!E?M2pzwq2pMme2RpueKPU%c(phFzyQ7hMks?B#ykElxQxcB|qC@??0pT zHYsp~*o-}1qpT?^K!LncGvZHUahN9ke)B&Iq7k7&-IVcK*#guu!5is~Sm}s|zB<4J zYvuUaDUOO5oGp%|T~!C`1SlRwAAd&;O(|B(rI_Tt!5+e!=vG;)DjFeLrdMo@45UQI z23R{qXlkgVGjD6F>O{?^l_c*xxzu0h)sIK>a?uXrg_Q@~Z-l&Yfo%JZHhs`BYw=x= z?LDqJlB;Qh<}CF*1^Wg*A<(O3@jHx)!Of^IT|WmFg2no7NSdngk6wgCMHij?)Z{ZD z9oPIz6JIuwd{1IoX5iNwG;FP>E*^bz*^kxE-XzV^XvBi&~0(!&k7K~HR)AAX<> z9F+ybF!M-_WIFSk1_8S+__NHon&CNX<@311K4~H)xmcpQ>eti4>dLW3PfwQ!8`*oM zeWX4Hl+;iK22IHNRvf)F=Y~$yHcu=Omig)_VNl`+aajLEwG`4?xO&d-vLrpKv$M1D zaS7d*QSGRlBr7YcJ4ast2}FkmJLBo+QzV!s>oZ8qLNJ%j&fZ}JAB=h9WWdut2NdjqTDwBux$<-v z+Z}}WOj!ul3)%IVQC(fMqMs|UpHx>Sz?i$B`&m^}K5UPFh272IegZ>he6HOp074zS zm-u&O>6Vt)x(0(#D;FM@e9N2Ta=9JH1RWUz=*gF_^={bj^lP+d5lXr>4ALx?47!#| z0vLSHxn`J4@hGy-7&CWdWaMq*wW2y^FyYJjZyxpK9-K#bn@M`0<&HEed?AlA8x%a_ zrVS4um#h8A&wZ*t7CKZOuURPff~(HtAn1#e0dR)hF2BhEboO{*P5!!Few0*wkiHC+ zQQ;senR?5&&YBtW5GQi%Y(UMmiIXqH&HC{C2cL9duo?%?+8hYEZYfeQzVuBY8V0xM z)S8v6wfo>utKJwM z+SZF92NQY&*>hQ$4hf33%==Ae0*HQ?H6DfkpP8C>_PV3Ik&A1N`tmK$ zH2wG7!jE;OJ;M~Bh?!G<$@lmAUcg79plE$*#a{M)m<&!`~YfB!sw_Fa9 z>V60)l1uaQeCL!l#l3i*o?{QR)QX2%e8UUqqmtnbtmWUiUvoSqLY^&0##@nQ3(HnA z?`=r{m3lkP*oe{fSR9_NzDJ!! zkDw477$jHtRl(4lQpBjFEi8qEEw}O&PY!4nutU@2OfYV#?YDNo0Ir}C=pBs10({g5 z-T?M$J$F;9FkbEg`Tk%8ZDH*rL!b_mD`*X&w){FIgwMMztN-j-t{~MSDa^ln)3Bk-|-X0dC}HHro=?yFIH-4lT~3vw-CX?@;MO0IF8NXVH$lyeRq8&z^aVq$K3bB1uU(P81Du zN)RL|XV$CYakAdC;y501C(pS4wy_@1n(qv8%2VX|H-3LH$7{R(1Jq$WvGWH%(g2>x z%%}cooTzVjvts?KWlFf9{=}FZfLJeB&U(`-i@d|*Y}2Q2-fIgu#PIDbZBz80mz)iB z`dQdXWt~{puFk{BC^0XK)>;gyQ&0TXFo#g%Z@|-qWcmpX$}j>XUM|1at8Cy7_}$j{ zTptvoK$|q5-{$2Re=20KLxHsfrITi%>eTlQc*Ves{E-_eIc~P;ozr?JTsz#$#PwvC z^^MXjU>Iz+&t*wJ{F2Z!y(~j(()lPos!}{IFNu6Epoxc+H5zwt`iUgTf^tFR?VrG+ z{KTl)pVKz+#xGRF3gd<=a_t}OW`S13!@&@0FO;{ju`%75p#V~DS_*Lh9e>-{fEep{ zs4n7eZ8>16E?B&8$`pg)jdw77JR1xrHSK!uG!*R=DRn7gvIolRG};M)ifavSs&Zz| zE=~?sCJtr;>u6pccVt{EP!?k&eQYynd}$px?^EY=5^gT8IjgoBdJSSw;6uY=RbW5L zKnVsEXd3qqgYFAd`7!@w*dB+mIS!e$x6>E*c0+ftGRAYZZT%)F$xO%jhAqYxV{*Dw z9zqQd4~JI(1zhglOs`OakSsdyd{n-kDd$IxPy~U{F}?C6rX8Ld3E&9?5ok-8@)9z? z*VNj5&1t`(0d|G;feI5q9SGwt)(>%%9|0Dbl+wP5bATXd_0$7;NGNiO)?s|xA!ApE=COd?EaXUD$f#3E13|I z?(UTAD;{C(Y;BxnTM~b%X}dwF&Exk}Y>wT0%9hTDP)!OQquNWK%o}ufn|0BQ%{vXBRm8ZCCQPb?*}wGbt0o!-1T(XAok;3`EZ z((f-4p5Iq^gkdPs<1Uo@6n3+%LIKt;q;S%Ei;U}YTG{q;fC$-CnSApGs3A%CxT6*C zpC?vsub*uZ^786Tz3wrGSNc4FR(qS$RW3f1!Gmb58yJ2z`DSm>ZMh;dv-kIu4b>3q;yhGuF)xG zNs;%LG{XD+rk^q#dI6?pt#bVB`g`j#f9eF#fv>{%SXYodBUTIcYZRp9{LbE;a!DO| zxH^L<;pW=BL)&MA)dwc-qM43N9B}y+tV5l;HyHhf4zadM?8_B>6_GB<%h2Y43-acI zbb&4aurX$;9jcpVk(F#QMwH5*uC?;iZ;yGI+x{IxSWtCyL% zaYc{tTzGLqz)oIkT#bcJFnCVFltUTCEvhq4d_JaYn+;s^T#|;)4{rvu^ViwM-{bYzE|A{~+!R>IS!yY;^4*s&AwSWRJ%lj!Ec7C3a12_g8Dq)l2RV zINsPw=(}^J?0!?Mp^=q`O_#X$irSZ+HCK_m-E1a z8mBA%Oafn!L}35Pw8=ig+(Qx0?bpB_D5xhLyqw6zRpPZwViunAxRFd5jkWRTR|`ImP9sh{){WHS$R970-19H=mKd( zR`eBl^2_OAjdn^04KdV%IM);#Sa_@PfX2thG6C;-swJ+*hZYwXHyI$#{0>$B=0kJ; z+_7vAA|{3#KKj-z?2-kZg88us^3~NoT5RjhWI);>a(b44*94T<^5XG zC#&gLRMLD%5EL6(E)G=Uexe=#r2{ew9&U|n2%i(nvq85%H45!`X+(HAnJzs1{;6)7 zb$%kpSUi7?&7PzmUEA#|eZ$*|8Dqm!ziMMxdst$o1|e%%>kT<;0wd^!s!wSkex5kI z{=BB6;Mcj@$lxE12Ypcak`@`#;1p(r(~f%?-a$FuVYn>H^=qf|$K1V?KUchKss}^& ziCDj6*Dc^Y0P2DTSjeEyY*hkYD11Vt_qx~+@q!I=UOE+&Q=V$wOZ;Vfw<%YnX1=J5%0U3 zh*JXmg3TU#UTU_nZ&rD$Y5QMgleh4G;0S`Sjo)4t>M7^Wl)03)F~9L(#7j+m&EnN! z0vj!&o27SaY7Tzn5K0j*(+VsOai8lP&^|#2>&cUUf=AZMPA$Io_dw0m-Qx(kEVli& z6v}Ynh)I3ZJP!61tu7-_cJnhlYE>F|LH-P6lhBb7F|bibtcXW8L6$#mz#pORBGWe7 zr_n4JCg}UPOd32K<347{#_)jF z;?cvLevz=Z!xZ}FWR66%s?lvwtTYk^A+t>r8Sm0^F?uEO2E5t3tIL0=g#fj`H4E z_HlUj3&!;0;y6^Xjau;zak6z$6c=c`KdgZwF$AIS+!G!uJ3|YBS_z@neh_$G&b+qO zo2%sa@0mQKCKgbli%Bk%vnIT9>9ELKDDyuEmmzMaYh25PK3Nxy0K)kiyVZW9?z&5puL@2Ayqt+mo*v%b z+FEUXbZ$rVq;Q*Na9rw8m#kwT?5RryDPw25r}@ci|BSM^g@kpdn(fKyFXwCY6f?xY z%pW=l@1wP)M6Ik^)K66Stg8cK_>SZjpbz}p_Mr#4$Cpob*Uw@N19Z3dN+G;l(x+`K z$Ao+Hw_7=~11WB{qczC8&f&Y6)gg&Rj3KSk#yD0NN7IqW`f2~^fa^ifZP~Sl7`Lho z^~$~B(&>YWZHJidFo>OF(-uWNn+||CP@Cgg& z!Xg>8Znok3-tdXBvj>W5hCd*86z?filU}kJBC$gsUmzzFMy@|r>U_3F{oAAtdvkgyMZB37Haiv@zWOihzWOegW8A>rlpA<$9R*QnlF-n zA3!N#hc)`C$7`9})H}RCHV*el8k<*xfYsH-S;+^C3g6) z&+^X^{{NG=vVCh=KfwmO$6p;`>HQjYZ?d2Kh3;{hUj363)?a51NW4QK53PDR9NgAD z*`vqC`=qt&3%L%%<$0Y^@d|ql1NQi-2X`4hvfRF0>5HtL-B@B4Rt`rm!Nx*iS9hM% zVD$FiMz;)&!EM|FErzVVxA~T0(q`o)xg5iR-Uw^ooqaXWj?Ag}9GMfaEDFe&j8yn1 zr72t?5TGW15gR*+?yI#{xrpnArak$UVT5udDziEq6YfHMF6>ShDW)wvzUaMqrGEs# zYf4FEIg@gOWI2<2M{RHqGxo1_y;A;}QEpC|DLa+`aNAN4S;PEa5L~L`L)+e1QJ69i z?HrRSr;}Dyn#Y$iP}>`NvfhWuz6t)z(PyR}HS=f2`Y1;H4Hvs^t z29w7%$LOQ#)uCOXtja1jaR!x0DmO{~S;788lP9G=Y>h`bJzjl%v)m^??li$}2dYSl zP$}Ek-tG%+O*NW(pj*63En(>5ruI_X%o_k@K=pnLiFLO+v?Pb2`@N3g&Uq{%k)1C=kleSDv?%?~Y;l_3!koq4KrOE(CF$}J78^bUg%E^t zl|vVQKUtoyth)wXD}lYRRkKO(pI4(eLm@E+QQq^7?>Jh*^rW*duxDo9j}=Xf+NE_) z*9W}|*IQe=V$klYDF_?wr+9jN)Y|@ys}|ZUJVyVBHhZN?2~jy8G{V!tix=4sqCCwf z7LRiFeyqt}5-OxIgEMmHZv{GkZs{`XpesynKi~g;Wp`iizTczi)w(t$#v@E!0KvIA z2S#$|jPMeg4Jrh+PRkeblbRxOn?WnL1g)z$t_<>a-GKonbb3I}aKYs;cRg%aXVQUsf zEa$Xy#mG;bt{9(M?zj~4N3ne~#>N7m-~h?2IKrWn)OFvmFSO33%!U~v($sjaAKiw3 z)$MzTy)pV^lZc#JB|;&6NS!dUQn4IeW<-G77>f;lg7ro(%>w)5`?1rEDD z987cH3&PD#gioZ;F=K;CgWE7x-#;~KbnHr)p;HswEfk$yqHRs&VAO(_tCj{w4*7M> zf}KTVUJvhfbPL45UHBEJ{$$GARbA6s8~j|q5_Zj58lbIXr%WccErxnT1LBC=YZkQb zRDSOQU99~?p%qE14$vzuUGjQaw@gA5wN})8jzFmAC?`v($bN zr(c5hu1=*=QrAVVp2zzXKAev}X0+xt&lxE+5b4mi_V{?NIO|$Snk-uCVvB$7D zTWb%7(22bjXYpwoZ!vnA7sRRUCG26T{?G;)s18>0*4M$xNulqd?+`jV{WV2&=7rMF>XgkI4?qf2RsIHe_@X zqW9Ug1`#jUJpQx<92Oql*j5V$t?m~oi1z&s>yN}~r0Xrx88W>nhWOXqTecWoG@^Ef z>#^Bn6-$eWdmQSOwr0%@j>MZ zyA2%k4rllWlITKoG>ZWYLrzf>{>f!Y9uhEZM=e?^eW361hTfe#-$%bM{cg6el3DNw z&pyi{L$#WDuMD$pols(AB{XVi7bGwAeQI|P#5>60qrUjV?ou?wd{d~OLWgSmR*HS> zzq>O|pIqq}{x!C4BcSE49HV&%C{s12I6)Yx@M}wN93R}cd`pj93XMagqPLfF%x`Za zP?n?0iazS@wo{OP>96&_N4mN8j&|;(-Y@X494OglzOQEJ8b5cWxS75+Z}9DQ>M^t_ z)~r(%N4(^hu$W6#)X_HdF7R6Ly*)YzM;&}!fBLygep+`uKl#MWZ9g|m!$=HzvH}-`p*JDVM5#xNl)ICglkKcgK>xFkltezYIA5U zBM;kP-82pU^4zXM^*DNB9!aJp0wr6%>HpUYV4Lrc8F-gW%caLir-m0?hIQ7U*&n-< zgIVxFzesOU`YM%zc`#j*I1| zDz%q_+|95u<--f#Ts*Rog)Rbo(8i$Wb#CHs-S-yM;S8-Cp_aMZ@5ptFOUApcNwfyD z>?_WA$^MZ;*d0y%ZaVEgE@04!30e^q#Bg6&gfOkT)fYB-Gl>q$uYS~XFaJ0^u2h~8KfGJDGhE&Er6C9gn}*j8JXz!N+{>Qs495v$ z5x}C|>osX`G#e#HU%dn47;7E^8}0C7x%)+&WY%IUznq_#J-ySMOcArxI8r*1TT)viBu9 zb<)cHJ*V`?Jw-fIL}dcU%q~V4*G2G?Aqm?m-Mvd7m+;+=Bhz5#7UGDDy=uSRM{h?~ zmR`P%5fSlJK^F3UytpX1B*uV#UO&nE$?sv`gHJpst}1pO##eg`3D%F+&odKRj86J_ zSLR3Zo`PFQ*F*RNfug-Vke)N!Kd_ux*G+L*q$KYO;i>1I-^V&~|5PzBVupl%zXp+; zVn@ZNrMG6%jo(-0tK#3Sqq6{Iw-}{MF1<1pE2~*s_k}KCc*%A>GjXX`OLHh_IG>&r zhe&4Uhs|@i;wnF&klZ9ldBu_I={sCg(4=%4 zUn$G{$oXw(WW*NESN)MP^#yA^;f5mhx5eF-k)lYA!yMqmog>=@=k)*Kt2ZAyQEIrc zUBNXzHp=4>RX*39tvdULS!1$iMt#fiT20(SaH`u!y_6+S*yBIgYtCbiPzXY6a}sXh zJa+h>BYzx+eN4vQAFng`_Q>E(+o2T1Qlr{klLuA^Nry z1V46Yk*iO5Spirv5fgKdQgVPO43&}NnPZNp`<^TOYv5n|Q&7ZM%;w`eZcy>^oQei# z*hQJ0wGd1gVfm%qPeGf+SFHf9h$EI!ofE%jORa2AUogR((!?>lXiqLX?BYXa45UOts1?_P_&u}WSnm^Rt5<2EOAkyhvJsOe zila6uf#Bf!iaPRS%O%GGmK>QBNOBfheyey6N=ynSGiAZ+-ZZcX4(&zAhdGN+PpZ zEV$OLI&Z)SikF+ME*jA?f}7f4+-xz4ZUazy0RDrarf%7@kqP*C@z?4eS-*3rAY){c zCGeRqZsis(*Yl#u37vSEXU97CgQT~BhNF{kJ_O*`@42N1bH6}-YHu!uj-Z{UTu37$ zI&}dhU^$Z`>Z>La-phU_VxCn1qfJk_lnsI?AFfXL%@W-*v?OXOm{WL2m6k8k6DILT zZ;rWlnLhxeZV%g>q`gqJ?tSaw?%y7npB2G@$VF=f#unmEr}(lQ7s~|?qj<^zrpkNy zNir&*`Tm1BHJ5aub&=XJ`KK}!hUR}m9pndb6pi+k8o<3ccoYB_wRfkHP>7cKS=JfF zsK@iiqB>PJD#{2$Drcr%oZ8giPM)3QnQSKS07LEhxDy~h?hG{}euX;y54$L}Rmu#b z-)WgknMgE=pXf_miZ-|x3iwXSftYwFJw#PGdGbj5FhUUJ+{!~5g*hk#X%-6D$SckO`rpQR#qfc?U3Ve#RuA(h0(oUPzt7cIZ#y4iTg!KxR?Ut#CQ{9ij+^{WLsi&$i;%pdVgi9I%HftiMr#-=od zHjQ#s6~zM2u<qg+=c|r!Wyr7w5){r7e2P$K75W892_U9$b|hq2*SB;j0vM) z%q8`cC?5Y3S6}7dB5Y>CbFnaLEd@DrjQMxHA+qBf#Cbll`er}Oq!eqO*2ZxCSZQsWv%(zZ?a=*nvL6vH1{1nxh)uKC5d~N>}?SGI7E5_XU#d2 zdQg=@nDz+MYEAq1L6~6|7QCF{?94@2uI!#zFpek-w(Mum+w^*$%P;cgoaK#x$d8-m zr9@u=;RW5aKPvl&ufICFr|BHtKnZGk?w)OWqRwr>FZ*Cq~Zjx-TMH9AA8P)KC;4h@Rn)Et0iV|smQ!FY!zj$}iThfrT{f@_m(i+`5$|4f*${MP?%>)#qNj+dSa zndmpn26fARt}Y@nE(6**hdUYYeRiWOvEEFdU@`;bOf+nF)+68Qd8PndaGm^iNud%c zVfzS(^-w#M%dy0~JY$a=7&l%jt_Mj{0cH!9uTo#Hcqo)R+M@2_4EQ}|*Ht20${yq- ziaQ#_j0@*7f&06zu|o?F?f}m#`r*`gi*01!}<4Ym>GLvw77uX`=Z9j`MmL?MO#F)^X~@&ieX0KTl6*N5n}4i2F3AV$)oTS zpZzU6N(`oQ#we!1w=6|Lg+qI4wbRlR+P17M_kmcaeIoWlg`@<19ifcJyq2P(X#3o% z*<#V@?})WndYYc~LUq~1iH=&~09b`Xf{4+L(_3`BfV?2*tDs_B(njO|3aMnZ2v}ZN z${BicnQ2}&y)wYS&&XD(&VCmg3bG`n<_^cz*idIW8N-4@PSXfe^=TItIt?F_u#}-1$&qzDQ>NinPN@a$Nu_-)}HX#q#Z!84}mI_==W?5Wz-1 zX-l*$?xR6*O)7HY$Y)&osw2<0b3c%GIGgJ164wrWE8*>UGx!_+CcV65jEr(IPtQkd z;wQ8|hIh@Q*?|krsato#!ApyEt)&HddG>l&xrIhb3+c#r^+0ZAA9r*iU<|e~^WeT) z+g$WHQs;bl++NUyN)$O1;}%rDBVy2^cJq@e<2|@$nD?t9~jK`aSNa4Td zcgit7Ub?mFx6DNE;fu2A75G0XegAc0*8kZt<^QU2^Z!4$!xpPoaWTIKN{7;WTk`Tk z8(O#82P+|1s%Hv-$Vj1(OA7qn7XKq7)w!}I%oz8iT{Z{OKpCW&X7QnK)kO(^aiwQU z(!7`cUbJRzDTrR@m2%4hD3wDkjsg2L&CBS%|6<}!r_G3HpB}G@c!}elZ1N#+;QtC% z0r^4|yDSpbuhs3mE`8)06$%8bd?a;7A+eCD4JeeX@x7r*NX9mbp6o0(tVjmi1;2 z5ZYMHX@1g^>|Y}G^NHTnH4%o}gan`(15r%_3Wf~O7=VWv0O?^MGB)sJ6_hBJIiYabBxFSRf7 z?a9n<95%h&nqLH@EXS8-eE<6mzy2P}wp#Y<!Ch0Qxc)ta}7kE$VJ+zU_ri@OuyDGZvM)(NsYlNPhQQkpH{N&gD-lG8ziY5zT!-b zUmdMNnNS|`e=}O@Z;?l3g!%r8PEhe|nYW1;?Z~cC@L71NP#3+oAnEtp2k`V0H%}WF zF2lrq=fw3k&z^OO4pKKatZ-e+XA|_2meXCcT1%z!owrK~nZvu#Y_;yQ3=#g6E7Y-97F=h*a&y_;z+=yZuv&!R#>_Y2rlxdGU*?<91gMfmPH)Cb=Q{g8YmS{b~bw zwK=snGbh39LsRFFqY!;s0Y=jx*a_yTBRZXWK*zQAwyPCV|ySmbS z{DIydzZ}AHXf2e4#_4ymwXUR=M?}nWCC`nR-8-tU{O7RY8rR^U5nPF9F2m4fjl|}Y z#uAdWt+ViDuHQ8vM1KG2`+^2vR=7Ee#dcS74sJjF=Sb~v7l*s=rCTa*0s4>>wg;MhRzq^-d8`xz7p<*3H_^OyFllTvA8*{yU z&lvwN?%x09H6QyM3V;%<&{ zW@51L&$Ni;cU0Vki^#{eGtR6E{jtyqjg3He8 zcSQRDI;$Fq9i$>!Td2jwKB=hz!IB`*)i zf33}ioC~4D(S?qM)V4Uvc=u=r8tX_7{S&LkXd)aUH z?-amgVQj7EQyejNw zuj)OT<;>%@Pvj1K03^oAG5;CA9&-d=M3rd>u&x1H8X{!z5l@4H61A==bglpzs&1ZN znoVvH>SF>*5!ecJM^fVW+0MYi@oymV(7u~aBxBplraM$`&wb{f=)N|XYzx*x#(K8V zKcv}TAgr6+(HCJ)P2#2EjQvQB^Sch5DV8^-ta71N{;Tsh;i z`S_l`apXg!0l#9@HgfJD)XHjDHP2`Yozeq#ZtTo|P}}Le+W7eMu^9YqYA;}jyCO8> z`xq5L$LQ6oLJPPnC7UO1DYd<>tG2lKV43yh{MRD@tRObM&S@F*KdGn4Z&Q0_y7xkJ zDXRtW_GzGtQP&3b0H+-`Eca=8V=@4!zD0mk8B}whqT%G^6mPp^hU!A@KgxY+q(tIF zLnS@qf3*}lDASb_LFBJUxrL~;RiZP)l3Oh~h*QGXCo(2SM#bcPy%O(uH&nr&?x=%-Q-BizeOidK82PvHVvZ?Fdo8oJ6ZhR|E`F(s zehS`9osGHX-+Uh+-oQxJmf93^l74k8nKMlqe*>5cK)?b;qwn7uegdJBa=nDcK*V;BNX+PC27JT)RAVTx}n{VQW7`a5)37BQLk=ix8)9O;9 z<;RXPU(3NxJs)Zx@xwo~g0hu&*5N|AA5y8C3dK~sSk*o_6 zSLs8A+G5&~_wLB%o|v&FL1zyR`Ykm+mMA)6XgWIIEfkaEIVdYAoeo?6pp|w_tOM69 z@-kXy#}Bd@u_k%;nrw{xSQ&3)#aQL`v71XXxpD#|VKnEgH(qf zgHJ98d|&#l#m7$)4hMHOU9U&C{3q{-jouMRdfC*P`evMgsx8>lG;LqaBnMo4j3XjeR{QKeB^=D^} zU{!=wOwqgQSE0YcTJ!j725Qx>oJlj)VipYmr8#FXwGkPx3K=G*A2(7WWV2s@e^78W9kOm{_<>G(-bKYOMk^Y$T{5yU&UZ(qJq?ud>qXQyqbeUP0VPT&z zBpKc0YUvS$oUmD@W0(8vIP7q|k7eVw-)Z=^t+S=s6|H1(gAtqTLMo%) zi_uCyo({-yva^_XB6tu3J*r;9MjaxU)xT$lS-dQ~jg!aIirlsF`>oV8oO5PTR=-P& zEhQt*dBUYeH`xh8LYvlny;)KsAmiF%i@_O<)RvT}5!93Sug0ZH@fCXWVaWDi@H zVRq}i>Lh;ATcpMDH1eb=dvpGThea4!|KOR2lO>$(jwNNsN)mnxgMy{B=GS}GNaJWW zlc~`i->pA>i2R|KyD0BWrW4o9po8EV8yO5L%L;P{(km?u6uZ=h=r`*~-u;r>re(Yu zi0PPp0blU>-Ab*~OFgviPU4t+qa<)H*>3uY`0~_5inx1bk$WZyELA=vxE+>PRBVQc z@-!Opud~wCxPz0w4Kr(_0pB;g`{l5LEgJaaRHN?5t0%qX?c%yO@@Hi7DXRN+kllH5 zpj)yy-3Cj8Kd@1IN63__6fakRd=P*3oB-XTMs~)&&vJ4{aLV=cLJwx5J=3u2U+qNO zIRBh28xl&=8(*4<%F+R$Nlqd?y;*nu;b1#8O;!iyoE_#)3~aIq5#0%s)tIO$d$#3< zDrBy7juLtd(sYTd+Wa5EjjX;G z9mxe(g{POf+|V#B-AcRXD{m*QM(4NWJ>kip-?!;c30j1x4UDqA409O^_ zN_GT;xsWh*A+DD*SwoViY?r1b^Xu7>k~eW%J}P}G^7b_oKW~n7I$n4G_P(a1#5e1M zsi{|kH9x;BVm3v*hjy4N=>d1HzG>-Vd<7x)npwRaq$q6=^T>V~f%vl$lD4_@66r}a zThDW6=&UNYggjR`mFNUHz7nvzNI{al+FR*=fJ(2Qfd zaPLGcIq#P5qw)8Sk+m$jacM7@QohS*!sPI*hef$pR$H2ntw01t0|b@YOKZLv6Pwt7 z{)%=UArxEWzP;S1Wy~gW>8MWv1C_>Af4!+qPUf^QCG6nCl(Gzhc-%AL&cUiVD62oO zs^^2l)kVBzo+pbFc)RZJ{IlHe;zyIG+HHknMUT9mjcgzP%k2G|KcX<^YhzKBvm1ah_=paLGD$=ayq8Xl;zF2bI3j%@=WMe!~hHd3cjp)f~fV zX-jyjv!&@+rJPC#7c}ygP)FC0M;+QjpCsO2{ibGOG+-^Vvkun`>j?lsQ`YE=xy_}q zm)>XGW=MTP7KqDB)=dgEMZ60zL-^u;<*XT@4tj}8P)#oKtr7K6NXQiZJ*QE4!#ts0 znQBwL{&`54(zR_`$TB^6pGCh>SOJkL*6`$_8*^|uQt+Igx=29g-npc#0z_fVt;1FQ zhdG7^%i&mVeE123vw57xLRnnwZkbUmn_SYdgh!^;kf}(+_Mh!;bfI zoUnE-F2+|a>o+T9K*9qf8t>AecDsN5PAl`~YSMa$RfuU;I&EB{NfLZB3MJ!fQwmpV zRs~It&W!0uTT<+R0BPZ1Bh9P~f=UUpIMC>!^1eR=LL0!k)yfPzG1?S7H) zRuUw|;PLoQ$0`yytH?6t;u&$6!6(_=Z~=Y`zq`R$GUZoNk^4Ah$Fb@&uVZFW=~!<| z`k7yf_?8cwGJl5RB6jxomyf;4^y!IKt8&yzZEi!*eVHaN;##0u2y;G_QRKd*j$}QL zZL49W{Js_P^tFfH-nki%x|r2U2=2k_%|BMYBMOtosp7hp@L^#|Jv&6g-^>l(w@ zPLI8twiZ~rxYDWfxCxAMYVyp8`MDEPev(k(&|f$I=u$s4pDCztaq2KsHD`*vKa`4g zztng#AfP0_=I{S)nAl7mBZ{Sr3`oRKd~(2ao5*=G%#Z8p)~`0zJUruQ z+EesYZtHJ@rinLGmskB&gLkSO*nSkaK9}Zd3SQBe`%YOC8K5K(h2Z$nr{7#$*}I`7Dl(Qbc4BAU^Bvx!xVmG1_gNEV`O2vtR9G2lNieLPx;2C>C~_AFdbh=?Z`M)N zFfj05d($&?G~j3ekr%Kum{XyW4I%`92+KrPG1pHM9|W(!SNmnsPLaJ5ndwk^8w*os z=?ZgFl?Ch=vUq4P^3!^wU8c2Q6}P{g=Q9ok-Zy;9kUzr?M#)hg$c#7osb-HUAS{rzxK&51%nX<3~7LJ zk(G&H;%NaQ^hjtamnVzg!o8e)Ph8v0SYWotnXs0+XF554d~ah~z%BBq&4g9I#2f)k zT81GL6T3jx$Hhq-^pNN(*7G&MxPMtI}!^tbDhU; zynBZ{4d=LQa4Z~O$QAv*;HptR^M#Go2m~N=nrs3=4HnY#zWH1OB_%PE*WbN!C1<7- zxq}G9+n&UFFJdcoL;+N8#^J|)Vb_?jQz~*wOn7bEn)%~)CQ|Xt*K=*AL1#~;49Td$ z;>;g%pWoY=k3d(*bjJ3)kG#BC&ZV3sRjF!u{@OC@kcWzVb$9k`N$uz~kQ+1$aJY`w`%+?sc=r!1TheeR}=|e#PG1NyJD z)D>Uv(5G>5CbS7fDG0pPTU}PNa!lXrpNd{E)rmY_@KO2uIpoOlLiqs@i7LP?`6!X` z01|_v$HK<2~yX)60-As{=3eX+cCd?Ck!9mqkf-RM~y5iSikn0mYiK; zJFt~aDq7C*Y$kiuCAat4avtyRzg1Sk(;TdSslh_cOUJzK3`?+OelWkgv0wlw$z8@# zXHyhO8)486tmVjZ!3YOEPDI~4ER`>@%`)=?U(;ENuofg_@YZgeWWK-s^5b#(kz-X* zdx+f=+sk)OWN=$S>Rd4E-fHzc{K5Nr5*R5U4a-lLOlD9toV#S72*w5Ha(g-eC+j_I z+KVmYOO_<{bk5rzZqILs{#e$%72{Za!@|OPPGr(> zZ9lw->w#)5_YOne*uX34;!ej{zKL8ujcGpVRa5Y(VdMJ zr_CF6ze(th`2S)%&u6NcdAo$;;%At-DbLLUnO+jqHrVCxhQG10f|oXZ(T6WSJkiMQ z(u!H)?y%eJ0_CcPa&&jkW)R04`@O9A&C#TF_skXBtK%!0nwm(DQQvacTE+&A=2sGN zE$mSFmB9`{yIX>DnfoKO4Cbj@>!<9i^@)~JibiEku5>zH)ExHU1?whs&-wf^|MIQF zK(Npi^u=MUz8obn_#tC6cJOF*?53F7G1;s!WWln6fUxVG_1QZ-%*OgKPXLDOivH?oj3zqK6NRNNTs4 z;^8x&k9uN!g>iK3uj)QaG7<%K_|j=^kqgIPdlQ=t9|TxPL z&g#^VAw|LRvjjTy_19B#W|eH4KjdSe{wzl_G{h{fE0#hl!B(5(YYmWTk=oPm*| zdYlFuiRPzJKJ}HWLP3ky)G#ZS9NPdwbPwap>^@-DB3kcJpIwNM-1V%u)MX>I?Hl|{ z>hi;TwP)R_xASpFRRNx(2xZ#aP{tIyuO6(rShh>z-VGMJ&x8z~rmnO>aN}P7ns-3Qat*8gNZ2-o{6=Y! zW|@qGnkB_;^Mn4#wR^q&qG)@!KKBVC)j`82dTru=IzOZ(&{}ofY5lS2zW&Z28^pUe zRSk-ijJ2FJ)e5Kx`ng{*cBdEyvT3)m`{#Ey$_S+lszd)I5n%x&)20f)&N8}g({7&w zCpcc!w*@)U(=X7%Mv+;GlGmBeShhV%#V(yBBs6os`GUDA{2@QN*c=&rgqYsv);*-FZP|MEg8RTKV>;PF~74+AJ#PxO3#IGHj`D*;9oE0zfG@^-x zxFquLB5h)=RoLb6jM(hJ@n8gEox5u(1Cf{TuzOuf<%Q?%$|)g#R|xVf+c-Yd?gL|a zY5eFpw|J{mWq7u*;D8=PlTD;%cGsm#J^g#RyCLTu#}w>`i&|x~V1ILJZ;envy{0N- z>B~csrHS2QI2K=BCXJgVAfj=dOQWxc!mfg6Zrxa~65Qi$L1H-5=DL0?#pEgtlb~HD z_KoiHyK}QU2Rf(6@v!cxv);c#R4V@*+z8K}NsoD7oF(VTa>s`at)_HAZav}LXeX+~ zHrP}2=oV}%{8h7&!Rhh+&}k~&7TM-AM|vF+B-{CFXPRV(z>RjerMsDvgt9n3Q1AIP zC>xk8r;ixvu+MPv{RZz;9!|@IZI?foZ4dfXZ&hBv4}F*y&06%E)l;Qxinuo0c95|g zySGn0-cG0m+<-j^E;h5ii%ZT&8xQ8z<2?~}{jjC4H}aqh!mn+`gXt+;bZmSZ+O1@4 zW?h&cID2)Bf_$gd^gyV^utIr>N6iEWdn-34qS^1c%o)QS-eCRn1bnBP=!si}ll=*l zk~%94UQCeLIBVqT1KHWok?_ICyqW9#nsB@t4PkWt?`f{e=xC$4Pp)D$#S+_Q6JV)G zDbA6=?TZ2($v@~_jr6=8krb0RDqU_0%>C?e^`M)T*&EJD#nidq-?EESxm>dk7B;oX z|EyR2>^6_4Kuq|Q7b-D(eQ>AoZrlg8nr1tw1h%i?6dc1H?HPBrEH9(=W8QaawCi@7 zO7q_#)1}-NgGGL^D!-~|Zf6&P3EU5WHjT9_gg~*`tb~Q}a>B zK0Tx{gR$fAV}^-n&Gq)MfszKJ->}W7w7l4_8|!7EhW1U|i_azH9kFC{QwhAyX#Fg{ zJfhHbatWCfv2%ZfZ}Wc8uZGXvpA!sWn@J;^Iy0jtf;4q(&^hvp76D#Z_}c-Xy++6g<;I0p7iKIBDIH+{K$ZtG{xqhcA62-U)eNn>I2vtn_) zw%&T!lhkj@Xl&FDB_5VAl@S@fpp1=fk5Sf~7TMNv`@&XY=uO%87XS3UbVb&W>hiH! z?rt)H=JAS5-}IriljHQE&f*%J5%Ghav~mLh!c_aGaj7b8-m&V=LPh_u7iPp`@cU zehuF@iihMH-DjMh+4R>}TdQLMf62BWt<|fcM1m?;7t}OkxSm7R>@beDdhe(|yn zcC^VXG77iO25p^I4fg+P+mpPBf)TlFDhR>3Szs1r0|cKDS?b3Bylinc`_mDp+BjJL zXK<%@NnLnx6h9vLP&Soh&{n@;tc!@Dr^|@TZ_lPx*cu zP1bwuOvLCW|K|)87Jw)IKgm0hjiMYM?q8;fL@)YqPafMHqycp<9;keB66-!XH|Pe@ z;%@wL=C`AzZ@ou%ws&)7}x|G3)1GE=3%1J$)H`Mul9NN%XN7XthJuCz& z1yng7S!sW#;3fQ!aS5SQ_LZU<#xc=(P+`3<3=7NX2PSOXWctuJZ#be5n-E6EDC#u2 zfG;T-h$SZJ9fw5^cg89LHv1{t#gKuylY6mIOY^{t z-d0)nRqejd@;w&;>Z!DGqmHa;)e8v5jEFv7q7cAD{hB^BP>yWX>rDVg<`KD7MuyuzcIfgLk z^?f!twEdN7A-RyTzBQXMCnC2sMWO8jURCo5Ud_VwY?5or@~g;lD3=Srjl>?;N7%&?xiE zQ!R_9M!fz$gqms<45Qq9Bbe_|bcNnfe{hPiJ0$aZiyP5d=>(+CSy?VyCzbJf)yQ{o2PROPmM1{EE&w0D!FDTOIA9{aCv-X1YH$Q9`tHZ$WZ=EBn80Nb)*5lm-_2B|#hSKnJfJ%U&-8{gUY&K9 zX&qe34VH}&g%(n_wAGhS64piOGT97vgs0ShaS)^Ac^?&N-q?zYiu4J-*vRnwi1sCT zNVGwa{#+9)xns3G@ph{u1<#g`iwV~-gnP%ZMLwE0;bBSC&ne_CqmP)r-lCTHDo z`yfZzamE!W$t=^0Cw0EWAd5n*fq6YFg^msG7N1Kxep`E5V2QgGJ3=z}6}xkuUdoYo zQTffXDSLTV>U0!$;&TI|{qP-y|BO2LV&gJh3mBV0+aancuxNR}mH{r(#Q60$?4TE}UX6xCuE%Jr+Xfoa&!**!j1Wgi&>#S6fh zu_^F;5B+5}JTIXAu360LILCP+q^+g@(Miylr1(h-R>~(WwVuC5nkKWFFg$Y=ynJ+5 z7WAib>}zlVJpgCEI^H}L$+nAiNW|<pAaxHmH=}%O*Ie`+QFogDG90jE8Wy07tnMV2y`_swwo`*U=*V;E$- za$d&I{ZYK(J=L=9-`snn&Ws693(eP%Gr?hP5d-@47gs^veb4AlU#U~&Q9(Q(EdR6w z)xc)!l>OYGxAA@&bwwpgS=So8>a5D=6W3Sej1tcp&6&BPgioQYGo3B_;I`^+EktAF zfZmZ6@-&mjcmIFeocUv2&Xlz^JT&bLFhb6L#adMh65I6)AK5nvs!Uy|I8js| zCJ|pY_^R4arD+ML;f%=Xjj2+nnR8!_cSmZJEH_lg+W5+r|CJ-VBe&a?Tk2_{x_?{TB_++Ohxb%qE*TJo zN-)Ycem$O8JtGCS=%{SE&E3aumcdH5`fw`nUxL&5zXxrt^ITHHv;#J`!F{$cgBFKW zEO1v1>5G&tjuT<#J}2EE-eFe|J7-yRaHhExU)+`q#Ukq+YwP3*&C@y%AUvL?|DF!@ z*GlL>|LRoQ@keafpo&eQFpNfJVG?_}y3YLX+_!>k2=*F`5%~CfkaZ16LMWj_?^w9~ za=Is$%#GhwFhCB#*-yc9MG$#i9BqQR544Pf(mu09?9ga)4?k)+hI&}4z zA9uU@&wmnC33-^O!$8(ZpLbf{Hl90QHmNbgni9!v#cvm8+F`H=Yxxzn-xzI)?bQJh z?%PID7`Cz)H&2Nu^%L4;({#LggZb&LWwX%G(4U$>9LVxK2+|F{8ISoeKOElZI<3Pv zJRFrO>*DatjBT|_N;^7oysvp9*#Eg-9Qp0S&awU;U3&I0>lxJV*3UaV^a_$@2@{n{ z4Lf^E|P-ZT)UaZ^KaMwrW&VLUA7=^mL~m?2rbAItf~M=2NR zTVVZjiM34Yk2xu`wW!&h<)v$QL39i?0}==rq`4tCA#E+qbE4Q^eH{W!GjH84vHaiW za>r#Iz+^W+m(WW)6wZw~JHwYQRmqaK8)jtBoZk5c?~kX2ZaYjD@Vsm4`( z*v=>N&rl*o?vwPRkQOj;xBgZG5msJcn!BiF{4871;BxB~rnaw0;G9POnTGZih6Bf* zf^H4eb3ZMq`+I;GKmu;djMC%XzyVJ}TvIYIp(YN0Oo8c}|Ht4nHcbr$`g!xDpXLS` z;-3i5`u;YVeNHj$g}HcM0-iH|=xjm!pB5D8=ODWmrPJtEvBGL9Osf2yo%?_TXUBDO zaE?BTT<4|MJTE1>e5!Tt)`&uX_4CPhThy;NukN2ZG~*UkDG_&OVZGAa7Ly^bo80dr z7G^!1Cy^>!K|9|@-Doz1H1(Oo7u>96-IuGDS+y;=pR?v$Y8P9MG_lR#m;D( zUUC7I;Xpp@H$hjM0lj*_9r%l$6mAy}Wt=*c#0y4Cj1|rX-PuQ|ZQT#=ZKXmmIm&1a z0~1~J&!lapvLIXgRJvdn$$T|G}WB&mLwIzI6;z>?iElYSFzlTLbQj|5^ znGZTHhKx(OEoBLdZ=IEVD^eGpg`#8@B_TzS?wO0h##i`6ZwlOuYkjd8ZZJ~ob%%Q6 zPK@IUPYm8}%hMIoWcN?s`N!MAhjJr0M#{F_iL>PvTQ~Lzh@eT|6sdmrUy-{d9FS`z z&V~~Dxr^O%n}2|Qfv=Z?x{1+$({GfNW&Pk1*udS5;Q`p9Ur-2@|1jbf1udeXR4sj8 z=<1$u?nR3dpkUEg%friQrka|P09_#Q0mqB_lIk41ChuwqJcX#LNaFOR|5>h4k z*f;6JMRPYGiz1qcO=X*F;dzUv#_{+>XpehP-}3+G7y=wC4wE8>$h$)|3e8=`xgceq z*KmN|uv24vUjJ26GPRL;u1p=jgV=x|u`eSAbU5o`qc6mTc-S{#BWz(~U7%-ubs`#a z%?XE|rO>4Q==5b0?S8A^!T_*Dfr;y(mXn=rTPu%esfL>8gsQ+$%@>Bhc2>>DJS9rq z1?XZ&WNDmZ*XrtDzyt8>=VZ@MKaIX}s!O6tLq57=_JMx*+A6A*N}$vo5-B%@Qj3a} z|GWNj=HDX5(5R0(EPeMc^5D31;qgVkKaJvqADo?oV_FGHaYBRN^kX%x*KPjpxVyaP z_q&@r+@e{WeQ2X>qyqjjxDdpBi>{DP8PB){^kXR$7+@(EnO?F}KT?pd{C{Jm>F?{z z@J6b+lVOAa0CiCL?pW103t_46^OJRGj@6;XMKcx`kqm4Y8Opv5zz&wAxvlO0O;@3A zlJkTY>7^V{3<1stPdR~7?*+t$!e1Z)&>h?he+o=p8#*YtZ%>RLe5K3`R{E0*+K^2< zjw1ivJTjB@W9KE;uYJ-{5lK7{8&!yhkR)}J(I_B(6fHhI|2{1!FlCVQBE+rwc=IeD z1mJOU3^&vG=8WDPDO9)nE&|Jr8EoAxDG|xJXbI=^o__h4>I+^oXR`kL`YmDG^BHoL zK*OUapRav>;ufso?tL5e_&GsCl3Lnf@&vF<4-WzNTCMU!(@%p30U%sU;nv`F{*grz zUl?)Wb#s%e^4U58s<4rk@lTy3jf=n%`>6b+)fcVL(9MhqbxJpRV>?aP(xh?oeR1kl zb9gxLz3mf>R>A;P8s~ojt`>0&ZL!5A{*a#g(_0M_IvOUGe~H>r)9@>R&cHLQgH-NYu>|S zFccC$-G5`Yy^(%eYg+5(REnQRVw3w`?cckk*x_dDEOyxg1D9RGOQlZ1>7VNX0E3ka z#;RO_4yc-S;yXV#ehZ~q))Bmt+hPJ)G&IEk+u^(`nXL(9h3bhC{d(beeTw-q0{ZfO zYB%oCF_E*3w%<&qwhYZjApZ+80V@g8izY^v=XY#4xTn&$N6(_rNOHdkRcE@?lVdT! zn^oj5l7S7~eYeq%f69kdYq&R^2#bf#Pr;ted1>ri?9u&kKUEu3s-yNoM_=T!#k%*7 zX%=#FDF7BoGN>%>{)3Lq z^sv|8%`|+dEJlxzsUMeXuL)TyS|8+1@ zNE+dmSDmOcau96+$sEdvhUt~WSpv;g>V3wb7>hoyTC+3I&sUv1IV~#xFi6^C`rp>l z^#OCC0f3x9QMQl5l4^duY3I}r&zs28?XBs%i(!GC+B3~8T4o&ob}}{9$iD}xK~csj z0hvWWR;rLW|K}h3{$(GPA8cm1i@~{?`RchS$}m7sZ10zbXAi}DWC9z%l}fA+>p^wB zzhL2a8#l~ZR`0doe>;lT1YC8$3+=E@^XI5`x!Ij!ha@vBM}(r3Z2GVQ zjIw#;xx3SFTJad007AJrGj7JAnH8lAV zuAf#cjZw*HfVXw=YULB|vSjtbDM<4*L7yuAKb3#-8&;-C(lo?aR%*z3|R>6RT zj+5R1&NsNJ(HJ2kvujmtY#R{JKosU;hY;oXJS=3z;<;qYlVQ+x9atW&+Fwv$I9D%O zyjnz|gaT7_{~WS5SS?*>Ke?5e30mRnp!i$Dbpz(=>p1w*rzSx=Upjm1_5IPXiW0rn zB4{gL+>J`xzZIpKG_0sdQ5AHEsYW9zh;VuMDPyPhH6ztSQmByT- zGeX<*OLbxGIai&OjU6;9B^(kkwhF)!Mn_&Pu;yy?(9NV%Q8=+Y+c!$K7&v=8I0sVo z^3PCdJl&@CAEt;Mz2WzB#}Wo6XTQw;Fp{Oxy1-gdHJGe$|L^oMQQtGK@dvUAp%K7Ts%gRF_^m~YdYzxb|RP!GSzl0Uxs4S-AUNoD{_HoXS4 zXa#VGOlO6~t0vw!9nt}AP#}*htE6Pbk#zSSM(xq^K%EW7nEtKA14DwXIM&IiAKp!h z_aK@n_a50ghClP+0rpHv(XvZT5-r~gV2~KCvN1P&{=>QT0a4^-NbcfhqQu_u@wgn@ zdXv<9?2fJItxs{$ab=kJfmQ%{J59~;YzjoICoMJ|pLR$a7HOXfm@tkh6IS_L$bK!1)tTyLcF4ig0BJSwJ&tw6Js@;DvLh(=4!Qb-%w zO=?CvZTta?$zrasAMeU^e*7@S9XccWrY{>jVRE@(!PIxHk}3VMD4cm(Ec+dnS25+S zj4l6(esY0(ra2!glMKTyS=`yO6@8V-hu`2yim^;6tP#MMK!g_b6SQ_LT<$#@ak@f&j z8`3Z{9V^v`sA*L6R&y8y|Aiz*0Hz@ikH1AEW=`?|xZc3?k!@3F260eaXs8~x1{n7v z^=nH=3~8N0q4a2lw5|m*_Wxc@B(NO_&X+aGQ#y9rU_@N^o2>?C!~%se-H#aakkBme zo--!C_aXu~3?I)0>J6NHv7aUN=DiPXTke+%-GP!?Im-an)Pq@_zDRd<}KV`E!9)@C($v3F2bt4lHKC%?lV z98}r>y=!_OKqu!&;^Z>`M7t4IL9x=jWC;&GUre!j2*3}v%9fc$-E(hipG|WIWfo1B zAd7@}uN86YpI=Uz{19$s3V6@|DH$h=8~x&$bS;Sa3cDIu)mf(DOV(aL=k2N;?yS7Z ze8J)*zxxH;*<=K0!1ue<0Q>2wN07`d2sg$Rle+@YQ1d8?ziPaplDe)Ta^w{=5J?S{ zUfTyR&Lbd^X^-`8w-ZpnS59BBh>-nyGiK;WsEK{!seSOa4|e6{%w~{3J_fMN0mni1 zI;=_R(O;m}152(jD=mI)mH4_??3vlh4{-Toq;$*^RniK2T+^do+g8F~Z53dkL=w?# zR3RChZ_R|8}r5{#1DtUNS>8A}6;cJ@=B^UEXH50z9#r^-e?CXvs(L_(~(}x!< zL^Rm7i8dy{6MNJFNzxOtR8^`8OI?>+ISxm|M30BmMz*OTkGM~6Y_ko}Y>qE!mOaJ` z(S>L+s&8C1+|1pUg2?)&rln(giL-*^;cv-ZtLI1=nFh9;VOTPID>+?*>3iD{zmw&k z;}|YZj4^<{5LFOq82~tO*l{#wa9lq6Gous|M`|O>SUS7Pohw)*Bnb)Jdj2J^GhySd~iH@h5;qL1(OazYRQB2D;vr6oXZWzxXbUr?UQ z$&IwM`^Oguw+d-NqkiFCqP2IDf&U<|iK3#+O25Kx`lk@<$0AxcJz+0G*?1XWJ{}TZ zbQ~nA<3|)yUwby$Bux9}KUma18#c=krJM%ZVFvd6Z!(J94=3m7Yo;u*W4%;Q>@~_ahkbp9{U8M@qsiS)vd0A&G?$csqBWgZpXWWcZo;>?tv*pOGi=U_;uZ_^=d5f4-}*6EMF z*w_FI6#$yzF^Ns(QruVO?rA*VArLk76bKa6(xoL^3HKqR-*QFPeZ=Y6XA`F`s#Y;{ zAZ0HAru5qIEo7I2aANmgT@0h{bcd=i-7pvd{H``15AW^IB2p0sK~t!~Yd@=>cRMVL z2Dm*roUE8^Fkd_89c138Qugybvu0dJ=A~o)Y&7o2Lj3@ktE{bZc`s>w{RM)yzq*_M zLFaWauBq{CB9X_oO2g#66{{!KgKS%O2Yhwe(7qF)s{){r7)1bHhNY@?S^b<5rpEz% zsn4R0day{_QoQ?g&jZy$-d{NlC{Gf~N57wPHm1oJ*s9m*WR3LkmrMuOak7fdLd0q)6x}MS2a85QHc= z1_(u(As}K15CTGkh=F(y&bRK5yY5+~H$YT)bXerlG;La5bOf3i`O*Fe|XdPKdBN3mKJ5-ps%voGCNHR!D zkap%0PfT`BDwTdJ?ZqX2G#Mmqz_pRS!}tyfJ$d4B%~H==gOT~#;|eux$xJ+X{8++Y z%-*{M5U96m~5 z-QGJtvm28GksgZ4U19%dc8(oiKS_%?<5>=xA3D`n4gp0eM>bW9Bw%^Z$oa6BnjYgw zw>z>jZTWLZ!$1dFh4a3n`wp#Z;+R?DJxkp{m!9By5XPaz9-3q^7N>9h zmsG-hN7KwQr&1g68-OAbHPY)bBhc^_lM?iUB#$j|_R+>-fo}AZC?=l*=p6OO6}bX- z=d<@6G;g$mcwMUPL%l>3=J_J&D#J%d8(n%~$sR{m#y&cIG;IZab${4+z0wv~?zmK0 zsV%5jW4>hXQ$HMJA-*F}Q{Z8x0POLgYOO{jVPt?`6cl#t-)hl+)LsAo@PFV8{O^tW zjlOpJRr;_;Yp(Hp04mOO266Hm)Xychd-su-ZMkQ;3Uau3RbpPUufMH;{6zl!Ip`P6 zsv7>BeYH{37kwc=2-ADfSWs?1#lz(jmnh4yRmq)=$3&GU`%O5sItWd&<8W0+wy#>@ zl%8_Ynv;@zdICMwZoNGfWfXagjYoIo{CQO#_z5}dl^{NAr{PZhVgd ziAg_n;)D0Nn929HvQNnETR2IdqD6}83HBvYc6w&}uL*J(H7Wf`LB6>r`mQrb*zuFm z?Jp6=Xf(oLvJH<6PWKrl zlNG>Qvwz?i`oMew8fp;Vg7z zqLk!9=UzWqZlTJ4{}9}NNA2RdhoW{|qTi>Z9jZlm6O*{JzhfOEtWLxT(G2bV13F}{=E1r3eJY3k=c#2J1&n7xA#(RlYW;!qGtMUk$Hhsy2 zHT+R-dx{I#8Ku>vRf#Pz$TPxVnaWC`?%)vt7V>#Sc~T%38;9eS;Q>ugNy;pMN69P>DNITG>EEkZ{!4^OW3 zbhFOGySL6h_qJo%2(tC|_F4(&#H%5P*Lwp|!~{C0Ax39lE7%^29QJ62T2H;BV^nX8 zr6+w&`AiP6t%uZ3u2CqIN&2=Pv{q<~GO42Ua@ZqO6TBW@afur@$~e#=DCXgJqSW;D z!Ti|G%?NEqb1)eB_<+UA&?01ZJ1A65{6)u{<>F3H7};pB$;nIU7T|^yQ#v4qg0F+u znOJRuf=c?{9Qdyfn~bDs_fyHi;7oPYXg}T!EY)_ib77O#i*Mg%LFz&xL3h3w+Cw8U z3F{mXejzqPVUuO9yNl1uNS?g7rtNCXv)7A3N&>vNpdJ|Vc#-)`@a>x)3wBPV~mGlM6)vXGQ6{|0SGZL3yOKMz8ojAP?8Sw#sjT1Z#E?RKnwT6uS? zYLDE=Y8bE!4~c@RiU5CjzH#2{C-aH-dQM56gOOqN>KGmFJG_a`J+Qng=qVS)#z%}` z9m&9wKJ3H9vysb-ht@{Qn2}`(bueZvDd4Ww2rYujnr??R+K;&4TG!2|&E0!op0>-_ zl|1|l?f#`LC?mJJu=b*uXAkVIIi7JKV|H0;dj)J4Zo-38!nb%%`H=BTWxwvW{I)R3 zNjv$$=ef6!zEX5>4-D|GEJ3FMQky$rCnuU?EXkj;IAZs~Ey5k}ZoA#&!ETV|5QUzs ztlzD^(2r>Q$sYVC$hh$p~ zuwA!dmW;HpLEDuv+5*D{0b0pDOCZ4=^`(Z(yp#(vdbPS!oK|raU|W% z6gqRUhZJC&YlBrm50_~RkS*%ydw%iukxp$+wMp!O#pTgiRZZ*081?yAp6t{J^rU0K zXC{_83xhDy+K`}}%|c=?r=obG&FSH84cPsZ#7T!W`ksSULeYawW{;dX>AP~4ObwD? zO8K(!9m8z?>eaMiK6dabG|&Cd>47ufO5LCX5$NHTx|o>h!oEEgtC&Ec3AoIt=oM2Y zUo>HC??T|8#<4yrowXf{elD#TEj3C6hFyv&yU*&QTZSZE zvt*KPF9m$KHFkg?|M4;pqke(9lt@MtZ!&@CKoR9LmS_?7nrP3AQVl7#_PMsnqM--@ z7uBJ0WBtuH#^(t1xk88rBMp8g6n9#eo~e4~-{@W#D3X(*^Fvn@@l z@?u$ay;nr|-V4hmIC%3GJYeg6o5c zs1*XP>QsB@=ktu(G(`<}{3=y|%e8=H+L4_-5}D`%}&CZ`?$c+ zA_67-P5FMkHg*#=>k;#G_JjO_oO^?LHD=%Svle)SBJQvuzmS=k!&tuBL& zq?HX}Bu`7`V1?GXC+@b$iV%tXiS|l|r2BU~^bg3Pnu5&jZ$mwpl$du4Wzm#SdaV|( zarR4fA|;@yVcM6>iFT-8_g5&U&?3-J7WO^#N&DKjCnkN|`|oX}DyvNR^OGvBdlz)< zHzAUlQE%y(2GamUO7Z#dl9r?#${xXK7-_y+G`hSr5^FL=l9PuEwa5PWhIN`v9OLH@ z!CK?YQABXJ1%za?10*NR^)-cC@qZ%UcK_Oau|S_ztE&C&sdHC}BOhD^INwe+@XaoH z-iRwj?>4hlZ##+9jo3%P8J1B96?+dAAH5Q>i0^gVeqqJN%zKk$w{|-kgLx3=#HiU_ zv1`9m7k#?3aUfT*%VPJ}zHOE+9ENC~Tn!6ZP?3kL&hbPn)AtC3%!8Jc!zmZQ8PRMg zV&&slB2Y9WaX#&92lsNlV+$(Dgp=@1LO=rWmgwKl6X@GT$s5Ob?yiNyYKQNHp&0EM z=$;`{$5oi-HD_$v>o|N`Z4BBNH|#nrcDj4vk|q2_G)bNXS8P%U-E`k#!E8Rm`r_f` zsQBLUS73r(31L^R80|QL|I}$Ox@;sA8d$-k_p4D!%U>Yh&Hn__GLR|6j?7B!c0#C? zD_C*--CBXI50S@8MCypW@bW2d*2dF!VvnPd4fr`db&sY1n}vz(QL(Z)R!?oiS+1iR zqp|Yl^evAC1`nz#42kRBS$c_{AU|vW;F88xI}YSh@nEo2=3uvp-DEAFd_Gfk;b;wu%sfV?I+qBu|; zIqTP9SAUr^C~#}6+nwzYzsZG8w^0yP6W+~G;f9G>KlRXC`!*PI(_5IYW_&4-Rg{|BV?e?mw9Bw_ylcmEq0*w!E&1Hjd_Sx^F#6qHgV%t54IN zj|7$vTH9nGxMzQXCSVqSw<&(-+X{#b$w@4*Vl)z`_Qxw&a;kZ35{w*5|0P z{F;*3FFm{dvhImS`%M4Qd$;N#Q(h{7lE9Z;pQAjoenQUR)oWk(hf3LOJo#5r?M@pL zF83Y1aJw2ZP^xmPDPc9MHb;5RPe{(W{Hm`zuPXiTxVrV^>vE3r>t6)roI~bIA=fr} zjDB*gS8bT#<(#q2Pk)O-O45NH2=}j@mOp3hjBM)===+nQe{{@;(BG~2j(y)d+IyH% zP9(eZ9z#8;tU=g+$4asFRS2NyLTrBk7-VQ%*iRjaTl|QakLqC^9K`OdgJLx$Gf|ZF z2yN{S^sy3xr*=@5jD`6Js6w8{13b9}hokMUN1$QLp1;g_?oHAYnH+Hy7X5VJ)W+)@ zp8$CLDDN!S9PHRB;lZZvP5|Qf!gLkeKWXyglz4HP8BV&22KqDoQTESoygefo00-Ff zMR?q7|IxE<<@QiSu@paN^mj$B#GNS8B5x@*sz;KaQ>9;tcbXcW5}L?7n5Sa^d`_9z ze@({#Bt$EvM-l%Mgh%*U37c41ORfV;5Gr*!1>yfV*_b`C`n1v;QMRs0BQ#FeN@#K= z(ju7Vo_5MwLOM6S2;W5>xa7Or;=Y7?9?zDk;eB8m!CX-HJbq^C9vLU)nCn5^=??M3 zZsy&sd}J+blGz}{tnD|N4GuurGkP0#q7GI<$`-?SE*~47%$D^Dv4;Z4d3mXOJ*p=T z$lh*$(M zz>E!Re;xvJG%?FVtdl(C>|+&#s*hS2iHdMxlFr}ClJO1GktF>=+Uo56EgGx3hGF7Hy4o{muCzkPHjKk1U%YfouAFFUI8F-x9rk%S{L{v#1GI!J@lM zQOd7dX5QtWyUI@6OkDRZdf)=pGOHYf%>qo`+Mdt1>ur2Vj(Ie^Dko{#T z`TODU!dOxQP2AOXeXs9dnAV$K-GZGmBhlZg@nw(4$(ofzV4Kq}=gr1-UXep;bkx_e zf1P17be<3K&sgmMS8Xy60{D5G<NwB;07uRDD4u$a=(JM7DKP>%0}B-gh0(?bSF`+%MLMdJU1HDxqUUCv3a_o z+a4wy~Fy%-p3f-%~qrQJ2LYR&IZP{~FuvR1#@2AO}J=&r~ENC+`i zL;z6gK5>GVS?J5%)iFgmwoYP12{RFB#M3bBIbCz_Ax_2z~_jRG#7=VO@V%l z(Qu|LiG+5+^xiEI5v?M&ybsRn2ji|tW&)l%=-OoF2zX;tD!0#Dq09?d5+&=JTi7*#0SVlt!kO7N*$u?sQE27A)W#L~GG z;fRTMPA@(pV8SMF#ZdoZ!Xf=>D%BaPz>mL*nK1794Z8^lF>-iG-K-qhuQW82{?i#Dki#F@bl)OPrF38Pn;`!I3 z+d2z=>VTNkZfC>)g-&<-q5FDx@ly2Ui5E|Fd-K_-OY4m2P%Y|e*kz}g=2^e>aHz{E zy}cCugt+FL-%^+9UD0W;zzHgxOLI~e%=)L_JX{vq<(};~5(@^S^BnR6!C}7c4ek{X zwz4E!CymclqgiR+;6wb=JcsYqb2J2)MwU^*flo=&gdP7kNT+91KWD+ z*Y<K(H1@5dpC{X)acT&zE;cDx(e6vJ$ul&f?foHmj>~Hh^ zTCX9Mu>w4nuH#BYjl<$yWqvM4qAs-5{0#=KN6{*$YSYXPaf2td{S2Iq=dp%)M`e@L zjiv+*WrvQ+$CrWjP2igW@?Oa8sym{6N9XTIYxsXx>oXDou*tbw`q%t}B>t&>&;FLq zX4sXUD0R?BtbQ>?J`aDFzyX>Y{M(NIV1wzu#mkLPD2Rf}#$q0whZi^6S(qq}NR(S%(C?rMLDuC*7b&<(D}iB830H_=;Hip&AP5pz^gG+o9_Qo==$%{F&OEBzF^ z#T-6(v?u3PGbzBocU-kzn+;jH3h11U(bmjCbph}Ac@JwEr@Bx**ciuM1I7-!7W8do z?3UFqI_E!Rc7zxeImt++JtAJ|xB*~`c;8Hz2*f$p9q9i#;tT}~37+u$r7f?xb_WHi zSU=L^L+KQ~EyLX+C!1N1aAp#Bq9g{Jbt~_jGF}XV;eP*_Bl?xXJoPe`wjb6{Q~Tur zBm{e)erMCYr#=1?cLfc@VQJ9h6V3&}ZInf;KHm;s*lyOKT)**5Vo|W~GUg%;hqrB> z%UMcp3}NwbvQf>wzF{{NOz<^~mU+q8Pvw_hIuPWiLGQRA^~=t)V$Ya;UQS6?!spGh z+-J8U+w|LvA=nLjy(x)tKhxL27$R+be?~rCGsE9C7w--p=d19CNrIGfyU z%E%aW%XPQSo&B@3c0?j`lS!oQ#^@1o#3U3-VkRK!o~@{fl}k^1Nt7bBelHaeH#3%G z%;v@*ahC12$AFfD&m_BSh8uIyX)jq0v%VhLuO!E7%W@9d8``2-Cv1>ES=N9nhX{kjeXECo2Jvo~DgAsrM_j z5j7!#Y#SUVwtIiJ*j{2T^cPpUqyu_*F8+lCwkhs|MQrJgN8`}t^=H?t?iFhi=n8o^ zfj$1*&z0@i9}LEHY|U(C9i+DZ)$V&6Kz`*^{GdO@ZyT2*HlNnx8+nt0i0g6yW_`bl z+JXX|j^2gn;=DtIiP~gd$P2(o7JN6L4x88Nd{E*Y4s4wEm4@PCt1-HXlW7P0ZBp+6 zIQvDsU22)n{`c@cpC3@|&tVGJ00bIgT%ou;I_cW1g!jz``Uh_OBDz<0{+P1IdC@F7 zeacMPsCuo+?kowDC$n6KT71z7`)okUWHfkb(kHi@Bi;f%FTd8=PPB=Y@Uw%W&CSh= zfhPgTk8h#wL|rLrn6B-Ctw!~XP(ml_cJD}e^{73JNR*NfOmNm6SkKDWz?fzD z?B3|6^>_9}vb3S<$YIy!Z!A`W15Tn6cxdgJdaY6qmZRRCKQ=n+%FJ=$&|Q_*Ad$pq zc^mMcZ7v`@Zoh&z;(Q|4X$#a;AfUm68=mOs#NHr7OM0lIMi7ZiN|sNGcF#p-E~n@7 zYBwFE@)-)U?Ou^%8Z#fZ{VTRr^5E@V{I$d42ImuPYNeqYhE9ycg5>mK*~S?kL|>Q- zhj_AIn3K(#<2f-z z+9&Jg0qQzK;m2-fJ$QT$1Bp8(#=oIjm=qJ{jB^DmyC3_`;D>ibUL|<@73-~ zS&cy3y!bULOfL;Klrea2x}L8O++V%_n@;qX$Swy+z&TZ&4*Fw(A_;2HW%=6^hln?Gzo^q(q`|K)p&fgi_mO8SG{3|eD=uRTC!CgxWgjGPny0}@pfR{#J2 literal 8545 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 literal 9215 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_2to2_finalize_1/00006.png b/test/snapshots/stax/test_2to2_finalize_1/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..82497e000274af8643c9f7f7857adb7ae5bdad70 GIT binary patch literal 10347 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 literal 0 HcmV?d00001 diff --git a/test/snapshots/stax/test_decred_sign_message/00000.png b/test/snapshots/stax/test_decred_sign_message/00000.png index 89714715d77d5de41393b2b3b10eeec57d6d7bc2..c496c71f6f8e58c181cea00b2422ed58a438e61a 100644 GIT binary patch literal 8114 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 diff --git a/test/snapshots/stax/test_decred_sign_message/00001.png b/test/snapshots/stax/test_decred_sign_message/00001.png index ca53da99978f0a4e65ef8587781e0effa2a564f6..bd4c85e8f3336c2fd1da6bf8f4c7ca04c6305ef1 100644 GIT binary patch delta 10272 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 XIpKe4{rQbu;A3WLb+z)c+mrtXx}K@> delta 10400 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 literal 8557 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 diff --git a/test/snapshots/stax/test_decred_sign_message/00004.png b/test/snapshots/stax/test_decred_sign_message/00004.png index 2eb33e0f2a387d452442e4ae97f4485208d9ce8d..82497e000274af8643c9f7f7857adb7ae5bdad70 100644 GIT binary patch literal 10347 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 literal 9215 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 Date: Wed, 13 Sep 2023 16:19:32 +0200 Subject: [PATCH 38/41] Updates following product team review --- Makefile | 2 +- glyphs/decred_icon_64px.gif | Bin 268 -> 644 bytes src/ui/ui_main_menu_nbgl.c | 20 ++--- src/ui/ui_pubkey_nbgl.c | 37 ++++++--- stax_app_decred.gif | Bin 129 -> 313 bytes stax_app_decred_testnet.gif | Bin 129 -> 313 bytes test/requirements.txt | 4 +- .../nanos/test_addr_display/00000.png | Bin 0 -> 489 bytes .../nanos/test_addr_display/00001.png | Bin 0 -> 492 bytes .../nanos/test_addr_display/00002.png | Bin 0 -> 313 bytes .../nanos/test_addr_display/00003.png | Bin 0 -> 341 bytes .../nanos/test_addr_display/00004.png | Bin 0 -> 336 bytes .../test_addr_display_unusual_path/00000.png | Bin 0 -> 431 bytes .../test_addr_display_unusual_path/00001.png | Bin 0 -> 392 bytes .../test_addr_display_unusual_path/00002.png | Bin 0 -> 427 bytes .../test_addr_display_unusual_path/00003.png | Bin 0 -> 394 bytes .../test_addr_display_unusual_path/00004.png | Bin 0 -> 516 bytes .../test_addr_display_unusual_path/00005.png | Bin 0 -> 508 bytes .../test_addr_display_unusual_path/00006.png | Bin 0 -> 344 bytes .../test_addr_display_unusual_path/00007.png | Bin 0 -> 341 bytes .../test_addr_display_unusual_path/00008.png | Bin 0 -> 336 bytes .../nanosp/test_addr_display/00000.png | Bin 0 -> 701 bytes .../nanosp/test_addr_display/00001.png | Bin 0 -> 364 bytes .../nanosp/test_addr_display/00002.png | Bin 0 -> 368 bytes .../test_addr_display_unusual_path/00000.png | Bin 0 -> 500 bytes .../test_addr_display_unusual_path/00001.png | Bin 0 -> 460 bytes .../test_addr_display_unusual_path/00002.png | Bin 0 -> 496 bytes .../test_addr_display_unusual_path/00003.png | Bin 0 -> 453 bytes .../test_addr_display_unusual_path/00004.png | Bin 0 -> 767 bytes .../test_addr_display_unusual_path/00005.png | Bin 0 -> 364 bytes .../test_addr_display_unusual_path/00006.png | Bin 0 -> 368 bytes .../nanox/test_1to2_get_pubkey/00000.png | Bin 701 -> 686 bytes .../nanox/test_1to2_get_pubkey/00002.png | Bin 368 -> 368 bytes .../test_1to2_hash_input_finalize/00002.png | Bin 713 -> 712 bytes .../test_1to2_hash_input_finalize/00005.png | Bin 368 -> 368 bytes .../test_1to2_warning_finalize/00000.png | Bin 529 -> 529 bytes .../test_1to2_warning_finalize/00002.png | Bin 574 -> 581 bytes .../test_1to2_warning_finalize_1/00002.png | Bin 721 -> 718 bytes .../test_1to2_warning_finalize_2/00002.png | Bin 713 -> 712 bytes .../nanox/test_2to2_finalize_1/00002.png | Bin 750 -> 749 bytes .../nanox/test_2to2_finalize_1/00005.png | Bin 368 -> 368 bytes .../nanox/test_addr_display/00000.png | Bin 0 -> 686 bytes .../nanox/test_addr_display/00001.png | Bin 0 -> 364 bytes .../nanox/test_addr_display/00002.png | Bin 0 -> 368 bytes .../test_addr_display_unusual_path/00000.png | Bin 0 -> 500 bytes .../test_addr_display_unusual_path/00001.png | Bin 0 -> 460 bytes .../test_addr_display_unusual_path/00002.png | Bin 0 -> 488 bytes .../test_addr_display_unusual_path/00003.png | Bin 0 -> 453 bytes .../test_addr_display_unusual_path/00004.png | Bin 0 -> 767 bytes .../test_addr_display_unusual_path/00005.png | Bin 0 -> 364 bytes .../test_addr_display_unusual_path/00006.png | Bin 0 -> 368 bytes .../nanox/test_decred_sign_message/00003.png | Bin 368 -> 368 bytes .../stax/test_1to2_get_pubkey/00000.png | Bin 12646 -> 8746 bytes .../stax/test_1to2_get_pubkey/00001.png | Bin 4944 -> 12851 bytes .../stax/test_1to2_get_pubkey/00002.png | Bin 10347 -> 4615 bytes .../stax/test_1to2_get_pubkey/00003.png | Bin 0 -> 10937 bytes .../test_1to2_hash_input_finalize/00000.png | Bin 8201 -> 8957 bytes .../test_1to2_hash_input_finalize/00001.png | Bin 15555 -> 15594 bytes .../test_1to2_hash_input_finalize/00002.png | Bin 8724 -> 9483 bytes .../test_1to2_hash_input_finalize/00003.png | Bin 5086 -> 5467 bytes .../test_1to2_hash_input_finalize/00004.png | Bin 10347 -> 10937 bytes .../stax/test_1to2_warning_finalize/00000.png | Bin 13590 -> 13902 bytes .../stax/test_1to2_warning_finalize/00001.png | Bin 8229 -> 8964 bytes .../stax/test_1to2_warning_finalize/00002.png | Bin 13679 -> 13806 bytes .../stax/test_1to2_warning_finalize/00003.png | Bin 8504 -> 9292 bytes .../stax/test_1to2_warning_finalize/00004.png | Bin 8203 -> 8962 bytes .../stax/test_1to2_warning_finalize/00005.png | Bin 13331 -> 13357 bytes .../stax/test_1to2_warning_finalize/00006.png | Bin 8504 -> 9292 bytes .../stax/test_1to2_warning_finalize/00007.png | Bin 8101 -> 8843 bytes .../stax/test_1to2_warning_finalize/00008.png | Bin 7723 -> 7805 bytes .../stax/test_1to2_warning_finalize/00009.png | Bin 8724 -> 9483 bytes .../stax/test_1to2_warning_finalize/00010.png | Bin 5086 -> 5467 bytes .../stax/test_2to2_finalize_1/00000.png | Bin 8201 -> 8957 bytes .../stax/test_2to2_finalize_1/00001.png | Bin 15593 -> 15893 bytes .../stax/test_2to2_finalize_1/00002.png | Bin 8724 -> 9483 bytes .../stax/test_2to2_finalize_1/00003.png | Bin 5086 -> 5467 bytes .../stax/test_2to2_finalize_1/00004.png | Bin 10347 -> 10937 bytes .../stax/test_addr_display/00000.png | Bin 0 -> 8746 bytes .../stax/test_addr_display/00001.png | Bin 0 -> 12851 bytes .../stax/test_addr_display/00002.png | Bin 0 -> 4615 bytes .../stax/test_addr_display/00003.png | Bin 0 -> 10937 bytes .../test_addr_display_unusual_path/00000.png | Bin 0 -> 12803 bytes .../test_addr_display_unusual_path/00001.png | Bin 0 -> 8746 bytes .../test_addr_display_unusual_path/00002.png | Bin 0 -> 13836 bytes .../test_addr_display_unusual_path/00003.png | Bin 0 -> 4615 bytes .../test_addr_display_unusual_path/00004.png | Bin 0 -> 10937 bytes .../stax/test_decred_sign_message/00000.png | Bin 8114 -> 8791 bytes .../stax/test_decred_sign_message/00001.png | Bin 12651 -> 12742 bytes .../stax/test_decred_sign_message/00002.png | Bin 8724 -> 9483 bytes .../stax/test_decred_sign_message/00003.png | Bin 4293 -> 4508 bytes .../stax/test_decred_sign_message/00004.png | Bin 10347 -> 10937 bytes test/test_show_address.py | 70 ++++++++++++++++++ 92 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 test/snapshots/nanos/test_addr_display/00000.png create mode 100644 test/snapshots/nanos/test_addr_display/00001.png create mode 100644 test/snapshots/nanos/test_addr_display/00002.png create mode 100644 test/snapshots/nanos/test_addr_display/00003.png create mode 100644 test/snapshots/nanos/test_addr_display/00004.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00000.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00001.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00002.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00003.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00004.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00005.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00006.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00007.png create mode 100644 test/snapshots/nanos/test_addr_display_unusual_path/00008.png create mode 100644 test/snapshots/nanosp/test_addr_display/00000.png create mode 100644 test/snapshots/nanosp/test_addr_display/00001.png create mode 100644 test/snapshots/nanosp/test_addr_display/00002.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path/00000.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path/00001.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path/00002.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path/00003.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path/00004.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path/00005.png create mode 100644 test/snapshots/nanosp/test_addr_display_unusual_path/00006.png create mode 100644 test/snapshots/nanox/test_addr_display/00000.png create mode 100644 test/snapshots/nanox/test_addr_display/00001.png create mode 100644 test/snapshots/nanox/test_addr_display/00002.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path/00000.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path/00001.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path/00002.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path/00003.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path/00004.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path/00005.png create mode 100644 test/snapshots/nanox/test_addr_display_unusual_path/00006.png create mode 100644 test/snapshots/stax/test_1to2_get_pubkey/00003.png create mode 100644 test/snapshots/stax/test_addr_display/00000.png create mode 100644 test/snapshots/stax/test_addr_display/00001.png create mode 100644 test/snapshots/stax/test_addr_display/00002.png create mode 100644 test/snapshots/stax/test_addr_display/00003.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path/00000.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path/00001.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path/00002.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path/00003.png create mode 100644 test/snapshots/stax/test_addr_display_unusual_path/00004.png create mode 100644 test/test_show_address.py diff --git a/Makefile b/Makefile index 7a7c10d..817189a 100755 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ include $(BOLOS_SDK)/Makefile.defines # Application version APPVERSION_M= 1 APPVERSION_N= 3 -APPVERSION_P= 13 +APPVERSION_P= 14 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" # Application source files diff --git a/glyphs/decred_icon_64px.gif b/glyphs/decred_icon_64px.gif index dbc4fdee994ec45b2a13d9610cdf445ec49aa641..12702bc6c58cbdd0e8e465cfdde3aa37dc9575f1 100644 GIT binary patch literal 644 zcmV-~0(<>ONk%w1VL$*t0J8u9D=RB`d3o{i@syO5uCA`*!PeH+6ciL`X=zne zRqE>MKtMo0KR*Bf0RR90A^8LV00000EC2ui06+jh000F4@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&t2f$cz!2ap)|lCkTD!80))cIfY3P`3ymNktTq_LYJwm-G@UubVKcB6 z&q4(kbO3Zy71#^ZC3Lpy!U$U>lKX+>! z1k0I@Bb`>88jRIo+8+mIM2Z>Q-C(96#C8qQ7v|?+!5;$bK>-<<@qGxrAkVsvU5F(M zfWdgG8h-@l7)sR4Q3G(C1qWfUOv~ z9PkDK4GDsigDH?D3t5Fmluw{YQ-Wo79CS_elzVB2}f)2?F8 literal 268 zcmV+n0rUPxNk%v~VL$*t0Du4h00030|Nkri0000$06+i$0_%*AsmtvTqnxzbi?iOm z`wxcVcmd{#qEX7WrscA0OaoPY&bUkMHsp&>$(e}-8c7M+`RM4G+PSFOSJ~=12P&M6T3%oRT zOhx7p3)AfU%sYiV3|(!V%@Bmt#yqY3eWnE-EiOhrF1^i;X1<&dtey^E&V8?qi5`CH S{|_*rz<~q{8ax=G0028p$$3Hm diff --git a/src/ui/ui_main_menu_nbgl.c b/src/ui/ui_main_menu_nbgl.c index 0afbd9a..34159ee 100644 --- a/src/ui/ui_main_menu_nbgl.c +++ b/src/ui/ui_main_menu_nbgl.c @@ -36,7 +36,7 @@ static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content); #define NB_INFO_FIELDS 2 static const char *const infoTypes[] = {"Version", "Decred App"}; -static const char *const infoContents[] = {APPVERSION, "(c) 2022 Ledger"}; +static const char *const infoContents[] = {APPVERSION, "(c) 2023 Ledger"}; static nbgl_layoutSwitch_t setting_switch; @@ -46,6 +46,11 @@ void onQuitCallback(void) { static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content) { if (page == 0) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char **) infoTypes; + content->infosList.infoContents = (const char **) infoContents; + } else if (page == 1) { setting_switch.text = "Public keys export"; setting_switch.subText = "Enable automatic key export"; setting_switch.token = SWITCH_KEY_EXPORT_TOKEN; @@ -54,11 +59,6 @@ static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content) { content->type = SWITCHES_LIST; content->switchesList.nbSwitches = 1; content->switchesList.switches = (nbgl_layoutSwitch_t *) &setting_switch; - } else if (page == 1) { - content->type = INFOS_LIST; - content->infosList.nbInfos = NB_INFO_FIELDS; - content->infosList.infoTypes = (const char **) infoTypes; - content->infosList.infoContents = (const char **) infoContents; } else { return false; } @@ -68,18 +68,20 @@ static bool settingsNavCallback(uint8_t page, nbgl_pageContent_t *content) { static void settingsControlsCallback(int token, uint8_t index) { UNUSED(index); switch (token) { - case SWITCH_KEY_EXPORT_TOKEN: + case SWITCH_KEY_EXPORT_TOKEN: { unsigned int setting_value = (unsigned int) !setting_switch.initState; nvm_write((void *) &N_btchip.pubKeyRequestRestriction, &setting_value, 1); break; - default: + } + default: { PRINTF("Should not happen !"); break; + } } } static void displaySettingsMenu(void) { - nbgl_useCaseSettings("Stellar settings", + nbgl_useCaseSettings("Decred settings", 0, 2, false, diff --git a/src/ui/ui_pubkey_nbgl.c b/src/ui/ui_pubkey_nbgl.c index fd45c00..d75f32b 100644 --- a/src/ui/ui_pubkey_nbgl.c +++ b/src/ui/ui_pubkey_nbgl.c @@ -43,7 +43,7 @@ static void confirmationChoiceClbk(bool confirm) { switch (display_type) { case DISPLAY_ADDRESS: if (confirm) { - strncpy(confirm_text, "ADDRESS\nAPPROVED", sizeof(confirm_text)); + strncpy(confirm_text, "ADDRESS\nVERIFIED", sizeof(confirm_text)); } else { strncpy(confirm_text, "Address rejected", sizeof(confirm_text)); } @@ -70,12 +70,26 @@ static void confirmationChoiceClbk(bool confirm) { nbgl_useCaseStatus(confirm_text, confirm, ui_idle); } +static void address_verification_cancelled(void) { + io_seproxyhal_touch_display_cancel(NULL); + nbgl_useCaseStatus("Address rejected", false, ui_idle); +} + +static void ui_display_addr(void) { + nbgl_useCaseAddressConfirmation((char*) G_io_apdu_buffer + 200, &confirmationChoiceClbk); +} + static void warningChoiceClbk(bool reject) { if (reject) { io_seproxyhal_touch_display_cancel(NULL); nbgl_useCaseStatus("Address rejected", false, ui_idle); } else { - nbgl_useCaseAddressConfirmation((char*) G_io_apdu_buffer + 200, confirmationChoiceClbk); + nbgl_useCaseReviewStart(&C_decred_icon_64px, + "Verify Decred\naddress", + NULL, + "Cancel", + ui_display_addr, + address_verification_cancelled); } } @@ -98,7 +112,12 @@ void ui_display_public_key(unsigned char* derivation_path) { "Continue", warningChoiceClbk); } else { - nbgl_useCaseAddressConfirmation((char*) G_io_apdu_buffer + 200, confirmationChoiceClbk); + nbgl_useCaseReviewStart(&C_decred_icon_64px, + "Verify Decred\naddress", + NULL, + "Cancel", + ui_display_addr, + address_verification_cancelled); } } @@ -114,12 +133,12 @@ void ui_display_request_pubkey_approval(void) { void ui_display_token(void) { display_type = DISPLAY_TOKEN; - explicit_bzero(choice_text, sizeof(choice_text)); - snprintf(choice_text, - sizeof(choice_text), - "Approve token :\n%s", - (char*) G_io_apdu_buffer + 200); - nbgl_useCaseChoice(NULL, choice_text, NULL, "Approve", "Reject", confirmationChoiceClbk); + nbgl_useCaseChoice(&C_decred_icon_64px, + "Approve Token", + (char*) G_io_apdu_buffer + 200, + "Approve", + "Reject", + confirmationChoiceClbk); } #endif // HAVE_NBGL diff --git a/stax_app_decred.gif b/stax_app_decred.gif index 42b500c56dcbd71e6c6fc0752ce3c7e45c9f02d5..72b4e2d0bd08c1d10e1b62d4d8ae69d94ee3338d 100644 GIT binary patch literal 313 zcmV-90mlAENk%w1VITk?0J8u9R#sNU#loi;Iix?d@u6 zYL%6hb8~Y)KR*Bf0RR90A^8LV00000EC2ui03ZM$000E$@X1N5y*TU5yZ>N_4Nhqe zRRA<>+W-TB1%+8E6|uT*d=WKUBSA?pcrJj;{Y#pQ(z_Sp@B?y7Rj)kiv z6u~D7qjPm91i|xJz9bH<^#eGc3$PReEdUb-PXYr7ii-#a7zQp91U3bZA&@N+h9++z zM=XR7awQESdp#01dLJq-L=UPn2D7xY3Ossg2N*_GJOHl`n^1rhRK71*29(7Um^=py z7o#Nw00sovIb$pcY-w|KlH3gp!4x!or02a!%>=`9Q5DC7%?}0#)RdhP`8<|P2^>hU LpuvL`A^-q8`4??Q literal 129 zcmZ?wbh9u|RA5kGXkcUjg8%>j>wsvG2m@0>Pyfo(Z}}I`;k$8q-LcB=XLTR2Go96# zcI~C@iXf-;3)ih{yP}xQuJ!cs8I2te_#$+e_)jVay_mCQ%K0??rQCrVcg2`oWX<21 g9Mv6e_CLY-eN;`_{=1pUK5_A{zW=e?&%j^}0JoPnf&c&j diff --git a/stax_app_decred_testnet.gif b/stax_app_decred_testnet.gif index 42b500c56dcbd71e6c6fc0752ce3c7e45c9f02d5..72b4e2d0bd08c1d10e1b62d4d8ae69d94ee3338d 100644 GIT binary patch literal 313 zcmV-90mlAENk%w1VITk?0J8u9R#sNU#loi;Iix?d@u6 zYL%6hb8~Y)KR*Bf0RR90A^8LV00000EC2ui03ZM$000E$@X1N5y*TU5yZ>N_4Nhqe zRRA<>+W-TB1%+8E6|uT*d=WKUBSA?pcrJj;{Y#pQ(z_Sp@B?y7Rj)kiv z6u~D7qjPm91i|xJz9bH<^#eGc3$PReEdUb-PXYr7ii-#a7zQp91U3bZA&@N+h9++z zM=XR7awQESdp#01dLJq-L=UPn2D7xY3Ossg2N*_GJOHl`n^1rhRK71*29(7Um^=py z7o#Nw00sovIb$pcY-w|KlH3gp!4x!or02a!%>=`9Q5DC7%?}0#)RdhP`8<|P2^>hU LpuvL`A^-q8`4??Q literal 129 zcmZ?wbh9u|RA5kGXkcUjg8%>j>wsvG2m@0>Pyfo(Z}}I`;k$8q-LcB=XLTR2Go96# zcI~C@iXf-;3)ih{yP}xQuJ!cs8I2te_#$+e_)jVay_mCQ%K0??rQCrVcg2`oWX<21 g9Mv6e_CLY-eN;`_{=1pUK5_A{zW=e?&%j^}0JoPnf&c&j diff --git a/test/requirements.txt b/test/requirements.txt index dd7e026..8bb03f0 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,3 +1,3 @@ pytest -ragger[speculos]>=1.6.0 -ragger[ledgerwallet]>=1.6.0 +ragger[speculos]>=1.9.2 +ragger[ledgerwallet]>=1.9.2 diff --git a/test/snapshots/nanos/test_addr_display/00000.png b/test/snapshots/nanos/test_addr_display/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..c29cb65dc7a27ccfee3e9f94ebe8b6a16e2c9450 GIT binary patch literal 489 zcmV92!LtM^!^XrqFFSC0lHGKwEi!9nm9 zDjfjeJbwLd+b1l>G*IglsNTi4&(YJ(k|Sv1ddL}qClBs1Fq=M`_y~YMw~8|g@!7R5 zJVrlgD?9ivVVu-dj}QN-V0tj!0Wm$2n7}1RP=b8a@%UbH5AG-T;7-!| zcjC1^mIlT0px4?FJ$Uk zap4{(6Z@MbELC{>Z>X}{yysvRGa`X#)e#^3HGr;6SS-lEe|z0xeV%xikXP(njw;h; zo+k&?nz|CPk;IZ$M)7%i-oNZ;1H-Fb|Mm#*cmX-+No06XBq&3;`>!eHkV@1XoY!6J zUxf1Px#tzF^x^t)_^ZGF*d?q+Ksk)N@c02uP9%>&UU^og>(g@Pzj(=C=?2XSe%EgOBlbR{XDK8JAn53 z(s&GQdP1+Jagji;Md*!RfZu2ZT`29|TDIN%w{U?*0Q)@Ah!#vAOad8=Oh5dDN(TTq zkINso-C;6A18Gz=O6VB?w%v!P8YwBraXu)ww9M1i7>G?NnKvb<_y~Z1w~CuK@>#)! zUuJy(*kZ-g3AYwxvet_lk%YNTxTjPW&hih(M^3(XOi#+)8Uul!v_8CP0VJ7Uwf+mi zn7XW=j9P;yQCa9o+>K0*p~Hih*U1cBM{lGS>dDIeB?(=zD6*v z!DxJZ1Pl$-^Ln&5&TZpVj`bD!ElNJz6_i_$NsbqvXEDXZ5&>Spo}V;wU`7SV?Q0000JK&k-#&AMe`>s8y^Y8CM+Iws z_r}c)bCy21ntveN+HsoO-J6g8yq&Kgu%GedZ+5qf8>THgrtPsLqtmjlKdVG((Pxg& zFa9(f4q;ujtl-~zAwB(IRJ?|?}_cO1t z>B$kCv@u-5wIyBtp+%_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display/00004.png b/test/snapshots/nanos/test_addr_display/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..4d13f81a58e4d37341dae89c3ed5deecc9a8d70e GIT binary patch literal 336 zcmV-W0k8gvP)2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path/00001.png b/test/snapshots/nanos/test_addr_display_unusual_path/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..527e9503ff3ef865833a68fa790ed5508879f5f2 GIT binary patch literal 392 zcmV;30eAk1P)Sv(hNI<-UGnC+_tY%ZE#BodRvdJ zepVuJHM@H>6u4)R|?_?<%9MNiRj@avQ+>B#8Bl*shME|ll z&H$Earu+U$6Y;&JL|eD<9dDNb$eGlTQY+e9%nX+lwEwH?xb_y&kD$JkOx5|pYMU$9 mX8l{6`a%l;00000bm9x>I6;gRz*QIk0000(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path/00003.png b/test/snapshots/nanos/test_addr_display_unusual_path/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path/00004.png b/test/snapshots/nanos/test_addr_display_unusual_path/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..496b56ea99d854afa0e23b9d2c516a8e7b05936d GIT binary patch literal 516 zcmV+f0{i`mP)Z91h1^>|5O@L%(zNeG?`RlJF^0 zegfk5jIW5WlYquV^T%)+5`JedpaQgelq_rYD~Be3IQY2}pBse5vn&dYQ9MCS4uYSl zvl9{R+uylc)&ZL-8mM-ONH1Vn$MA%4ND3ObpDc&O%oBY~%%<1I{0N};v6^R;?93i} zggY@g0(gK2iD;vu;ZgxDU>U``}Et z_0PnA>o1_5dK=3w;F-`EmEHfiW-1I5inqh~%$bPX2;Q2_xk^7JiB1BR_;&Nw7**{0 z8l4}zQ)F|)Nw%pWD<-Hf#EPdI9H`Yt_&$eMNn&Ia9mebMOxYyaR0%h18#ESAJ5>`l zAC8DDQD}VlS35oGXmUWYf(Ms3ngo1BWb6!=^Z?jky#qAo^MA&uJ!>(6_^&Nb7Ds_< zR3_Qlir^)6D#5MaS(*>8?7^;WRdd%QX+}WX6;o8>jZBfB$kkpkJz@wq@#rA5ZAv&v z#|OqO7P)rE*N!Os?r!J>dXsu3{Dm;C^R}9&7l*@fPrLvP;b{a030K(w0000iZG=M}5JL)(NF)-8#8~WG+aqKAmDTs{_=p4e z(^xeg1Da<%^$0I2ph=9U;{)(NdI1$qzoTSXn|~$_@Dm_@?+}uJ`45w!jE6H0e?!>; z0QT+JkINchOw~c2B~T^u9RQX!Mo%|xNkM`3klccq2V)G(r(Btt64dw;0KaWD&TO)0 zjV(Nx_W@uTOV15P32_-dB|^f`_Y&3?waG>OhvOxc?-|`jg?pny_)71?OaZVs-|GDd zA-Fode={-$Pa?C>lQ=t>m7!wcMFQij%(Piz0jkXv%S2#xCrD)_{LE<@##d~;-w__; z;_X6I31PP+t0YDnS(7;1oW>HRq^hmRQ=8S>iqNhwh-#e6%Mqc{=3cxLjkr}^?!Wf7 zBFc09HLUD6G-<=Bnh^WmYEq^&oC|%5H3mS;16(H$PslJdwcLr={WcDkHtcpZ1|US& z*dRemx^uF9BYI0nq)I2ei zo5nDBdIfKb@nHgImV(#60AKF`PHEJgEor&@6CB7Dpnkt$%nH_0RJjFZL$t)S)x+rke? zzTssvvL%y@y_qqKaPK872W<(i=I>6N-nqc-Ntvrr3HVC&X{G{{V!l=V2~nhm`kg@y zMuJ^vB!S<<@~X0W%`h7xJ#i45_6!;7e0z$RLYI@U2`^AzBTfNS3fF2u2ws5rjQc~z q3SI;O+n=xkhJykC00000fC22sDaOL^QLp;|0000_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/test/snapshots/nanos/test_addr_display_unusual_path/00008.png b/test/snapshots/nanos/test_addr_display_unusual_path/00008.png new file mode 100644 index 0000000000000000000000000000000000000000..4d13f81a58e4d37341dae89c3ed5deecc9a8d70e GIT binary patch literal 336 zcmV-W0k8gvP)2~0HpzmfEq+X>qi1={jS@>IWx{qTme2dKsQvdi!wcK)L*q?JF5hHG@}Nly}@Ze z{B1uq8kh)3Y4J_%-D83$z@AcU4fL<0^+5&HO1M+GD9a*cf4m4d*92XZ@3Z0u1xyvx i6htOOvOgh&kT);;W4R3)B~MHM0000KXnwA0p00000z-Mxv=Xsv~j|};@ z<2&1cQeF9Pd^*HWwgD<)Jj7}^j^i3Xj)TbfN3uw+0OC+m4a7C#AW>3fL`Rdkd}Ke5 zr~u+DXYR)|v>w+Yx|94KP;O|dM?>j3J-7E{2B1E9yA@n}Iv4ijsUh>s{il@jmAJOO zCy0GgYo}U9KfehB00000fEUhJ46&{rW5oWnE8iY{yQYfTY-2p~;?hpbzo3K>@?KGak^BXkTk(?LKqE&|R zS(lxf_i*{z=ho)2tuwtbcl!u2Q1P4q>R(qjQ%C6 zhAttr6`fy~BgQQe*3K-GEYYSNqqNg#S2%tU(<0Avq$s})sUHPSMq~lvM5&*H}4o(j$uG^A&h zJ-Ngz8K{6&#lC;j*u&`7G==y#qs_^kPHHl j3<3ZE00000z~}J`zqCQ$s2e_`00000NkvXXu0mjf@^wc| literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display/00001.png b/test/snapshots/nanosp/test_addr_display/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path/00000.png b/test/snapshots/nanosp/test_addr_display_unusual_path/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4087dd89f1ea53c9044584d11d3430ab40d0856b GIT binary patch literal 500 zcmVocNL5GvWu!S3>VMP zc<%ust$p1=EY_L^4~mK6l_Dhl8A6E9H2;|xQ{vC_DT?I!h_dzVRmk;00QxYuf zz6Ok6-#jIl_eG`H+1F3q+zp*!gAuV-R~JpDlGEirA+AeN6wR*vdV( q?f1vc6!cUu0000000000EaVsXKV)@JyifW70000}z` z?&-JIox!g;vLOvry@8CZBkwSL9L1fda<$W}qjL@#qs_kU?{~=(wEhj~N%v4Yw#t`z zR~yORJO{g$pkwXC-;sUA?k!h)E7=}^8hg2Oy=-6BX>YXVT{QKc4euALCYkKJQBqCz zoiPV@Vimd*zr%MTy#N3J000000000000000z&8JPE6>4Z7C4vy0000{edz=FR00000K$-X6dp~w|O@D7U zU_>#>a-k2z60q-k*hs>C>>d}W5KDk7i5^y%-)Xjld0)pb4M|UCw0034XH;vQM2=9FK zePpUB9Tg>&&XiUu+}vs5CbcGUnJ=(e&K<$Jdl-nz{~d=+KFGx7B->%5|7>1(+`@2s zd|7@r-)%M{xhuZd_G_O)!0+n;`9}S0&r0Xn#lyAN>upwdNnFTwY=sAEKE1^!<@sU6 zoZ*NXM`nx9ndBhpu<^nAEsMKp#1NEt?AiawSOEaQ5+r7pmn`w?=*psIe6atre1Y@U zrA>ML>y$nJ8#7tj!#?ss>}n{@zeF4M!Ur*P`N-3G%L+cy1Ka}ZuVdEj0rkbp%1hX_ mMx+leZ2|xQ00000X!-}bzH^FOl`lL10000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path/00004.png b/test/snapshots/nanosp/test_addr_display_unusual_path/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..b79de80ccc770decb63e97d35ce1ff63ebf8e4ec GIT binary patch literal 767 zcmVRQCbW-b>6D`{6 zlIyv}4iJ+CuKipO?TmXKy^{53K>5I-x;2#Eq^~`DRyv@LybT3MOxKl>bsE&UXZ$Ip z{9E|!I3}3qq<5TpEBgM2Fd>8xLdbXGrlI0`;^k^_vKX`yiK8hnhz`xWLj8>An&8l4 zn}_O;w*6}p{Are(N}1OxZrBzgAG%KuR0{AWJbGaURo-DOsJptshKGb1D{I{j=iZ^r zozZnz)neOLxRDt#E-`FyvUJ!P>M*@HDs|Gu2Vsx?HV%&g83*VHE{p&l?`;C}iAdW| zxa17T0EZpmIbWX{v&QW031oP=IN5E5>)2f*lWM34e4+%OecjJVGfo0Zq(e$-Y-F?p zaw(=+tu;c&jrObH(DP(!or%V}bdZJyX2&LhMov#0o=uR&B58O1b7&We%C~qUwuex0gGl2T&jNgi>uYC~A8BbXz5V8RyAC734N=uB>3aoJ<=& zk$9ZfnkGmQ$G|G1*5ovd%5*6LH>Mr9E(8r5bATBKv`t7qQ>xXWYB3|;SYEa38FRoC zTjx5djD$O|x5J~?I41w=Xq`5sjRw0~zFK2Meg#TzeFuQyOvq9~o-9s6iQM>GVbbeg zhZmh_ikb;+QVb`McnKkd5JJd%5clv{J9`R`c_)1HTUeUMIN+7DUmoNDlaos79eB0_ xUcfE>Rlym|SBVdTJ76(%03n1BLI@$>$1h1y`Axivo}B;y002ovPDHLkV1gu^V%Y!y literal 0 HcmV?d00001 diff --git a/test/snapshots/nanosp/test_addr_display_unusual_path/00005.png b/test/snapshots/nanosp/test_addr_display_unusual_path/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y7f*SxOU{AjC~-u-foLXj(O7yd7( zUu*rr+)c5?D=|uSzfp@q*3yH0@!eaa-dXh3u!`7U=jJaCOtx-s?e6kU zeDGCK?rrkb{>;w(r&$g(bTDo){54IY*1OJqfA;x5cHdNN*bn?OFeHuF|FZKp z>zX;reRpZQ#c%Oie7>!}>GM?9B~j1P>~>dwTcKRecq7QmmhI>I_15gYbKbRBzZFg1 zyl&I}-J%6=1xijnv%6ipe2?qVOs+!>N#C}=V}*I2!C<=lgelBlwf5Vr1c`aN`njxg HN@xNAeEFM! literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_1to2_get_pubkey/00000.png b/test/snapshots/nanox/test_1to2_get_pubkey/00000.png index ef59ec33cae7873dd8319576fd925025f9da36d9..ea3703ddc3e8d5b9b1e0d83d994e85fd5659e057 100644 GIT binary patch delta 662 zcmV;H0%`rd1+E2O7EL`f<)@%@kFyX0f4C`KF2?n(N6*^Gd; zKw#uai4Z~vA%u|s$$j7Ved9j`_8-UhX#pv_^3V9RiJ#K~T+Hz>qv5))SNU~a!Uiun z#o-7L4i(WLTw@lBMzW3RXi-;}?B@{?Ae;rx{k|4Tk9#A!lYjGjKw7Y=UInS<^s{@< z$pOeuUM>Z%HC-Dc^E9w|=K7OT`a0Nmye63Yq_>@VGy3_PFd>8xLI`=|ekU-iwiA@Z zzgF$bqi!S465$}sCo=#z0)_P^Ob-8ChPERhVdtPMeIfGwb z&wa48G0T?2t3!Wt1R%3OEc7BWkY0iof+~9YPajkhonM*&xZTBDXkehPk$pZ;6<3cR zN8jT1gPU*^0cABkg~u0Yu_A#9XH!)m{#3Hl^B$A0b$^y_9@}=N4`#KGI0i1rSz%U3 z8+su&^!`cc{gY_#H++Id$-@UE*Ng46{kX{@R`w0X2V zk$4vxH-8l&{&KvODIJ-M?<|@Y@vH=?@{~X4jxXX%CkmdeN{z`;cL0KS0394V!)1SW zWv6(Lp#8!Kh<)VEdhxAB+~U1=RK!!QTKtZw0PaF~BeTSuWl#we0TVaLzn2YfU7AJ- wUi?o9AcPP?2qAF1DMQNuy@&1?Oz4XIVhUkS57&*;7UkMRH z)&m8amI43(0002MXL6qBd7l1{4EeX?JKKO#UHNZ(I>b-50V-lV#A-N>;~GDXgUI+t zvPiA~;!siz#5Lj|QBq|@N0YgHWIvCn0OBlX?#DE=9@iqelYjgkP;O|dM?>j3J-7E{ z2B1E9yA@n}Iv4ijsUh>s{il@jmAJOOCy0GgYo}U9KfehB00000fEUhJ46&{rW5oWn zE8iY{yQYfTY-2p~;?hpdGD#uT3Z%Y!Py@0S+fY1Mg=7?`OijKm14eRbQlx)7gyvC8~xlA+!~pUza1sEfLnvER!tJrX8cS(`Z*X zeh||l&vT?GzYVD$1x`j}3V$o+X;)8S={aiKrt_2?%%K-$B&}?D|B9Z89wlVlPVJQy zKz?<+fqx~--L?7tDGyh$$RmE7TOn6HVI@n9(UkjR;JGCY_JAVQ$Nq}hzhW7TL0A6v z3g|jW%X-oqV{M%48J%L!;>O>e3eFZZq-T{qxx_3PsDM?)zJJr$!|2vDh4?q4&B?fb zMF0Q*PXP@8d^Z210v_>y!k-KRkPHHl3<8i00v-SW00000z~}J`zqCQ$s2e_`00000 LNkvXXu0mjf+bTvy diff --git a/test/snapshots/nanox/test_1to2_get_pubkey/00002.png b/test/snapshots/nanox/test_1to2_get_pubkey/00002.png index 9088cece139d94e6aa44cc37a3f242f8a4c18e2d..2fda19b19d7472c1543455e4b24ea5c12b56ca9a 100644 GIT binary patch delta 332 zcmeys^nq!DZhatMvjR^;;^sGMcm8|aN#$2*5p`L1sq9C+zqGImSLuda1_VeDH9XcW zdVXucuYKO0ix-$R{bT=|d$)1DA(vta*J-VTB?FBz~##hYf zX1i^v6S80z()Bk-bg} zYd*d^`}dE~yDLG)${*vd#&B`3=l__Yzq-z5+K=5n3_KkY4$_PBJ1=g3QvPN6w=?gP z?OUER+?d~{_SZKu_TJ6mx zP~`RU_=105-=A}J6fS4My85}Sb4q9e0K?;)!2kdN delta 332 zcmeys^nq!DZhf>+vjUGp;PT6JH~d%KIla!{@r8yC{z)9)Yqo|6a2`3di2(r`0@u8* z+Wcs%nBM(zjY5$tZWsP9s9$US!Q4%;#VavNb-z)ILe|oQeevB}quyEc)v$`#U+3m8 z4otRgZ{-RJKVZgww5Ddm-*oAa1#_FK`U81hb=NB`lx;{lH+NnRMsU?&(iF6SAScfT+VnS z$jg@P=lb>5uI#;Y-nCf26;0l}ZqxqVq6KdSN=`nryIs3{kL%G)u0st;-?qPFg$IGb ZbomKWn7?Z6w^<1i^K|udS?83{1OQs&m1+P0 diff --git a/test/snapshots/nanox/test_1to2_hash_input_finalize/00002.png b/test/snapshots/nanox/test_1to2_hash_input_finalize/00002.png index 4ae54ff9811f540b7bfa4ff6498913d0d91110d8..3814bb9c8019a14e6735815461e9271b6eeb6d97 100644 GIT binary patch delta 688 zcmV;h0#E(P1;_=EB!7=dL_t(|ob8)ic7-4eMQK-O;{1o?T>9avW#z>QiqLxY-;EGL z!ZUhHA%qY@2qEO1?EAj&JN_sr|L6FeZ9q9)`EPuh;%l}6E@nK;*|2TfA>X!5l))vl zm^=f7L&a!sjW({*8FoCamqTz^U_9~0Y-*93E)^tMxPM6bUI6G8|fguD~?7%HwO!C9?& zb}Yd4M`s=SPKV}+)68CY`s+vCmuI2Br#oJj1}~-)13{`lSM0l>f(9TOv>7Rrz(&)# zp!)h+n>h436Ms)EEk_hKZ)9dFFqrPOXKG1oSWhzU)OfV<%uQ0~D)d?r)b)G;YA8-; zO{;+3{L&ME*y&;*2qCV#JG!O;^$0Z!&mtXwU}qBrgrvZ|z37x|%=$)d6LY3&IR9UgPA#H-Mi7@OwZNPlg1-HXPeI%Pqe;>4i*XeYS( zCvHdAo4zFgx4)Q6v_AbXaFNt0>oG^iW&k2Gh80(#_t0=MV=xr$Ui78Bms6~NLMN>x z&2)-q10n%au=~%)cSwS>bY2sa3nrx$^n>gGmdZ#6+;Enn=bVLly{x3rPelRr@9{M~TbeVp!hnM$S z4EBKF)s1=P_7a?kTGG$Z3Ae=m1K!LM|BzXh1t~WhLI@#*5JCtcgb+dqA%qY@{ubXX W4xqnDF(@$r0000O7EL`f<);r>VRUGm||6eS6%*$k8E_ZJ3) zEU~toln5b&5JCv~Os?y?t_%OkssDC-?{*-)LiulE+QiRp2dbF)FlR%~`7X~ni#mA8 zE;i2q5l}H3L}<)HVdPcE476ygOP=S586biMj{QChWyEV4eSebudq7&Sspf(d1%2<{ zvois&Coh+RdrjAsk#XwOIdlCEh3`);bB1GpXS%#3?$2CUQG7l|g6Hm+^6W9}?qUrtkiqxl(G;La!1|TW6GjMoLp!-q61J zc7_rVuAagz#360GJG-U><=Cv%f0F(LggY20={O8Vq$6kGu${=L8tM!vu!7(A5Y2KO zat4?q+8@PufOHd`9&=*(tI$Y}YaT8lSWEZ5nwZjihkp^j$@G|14W95(!nh9;6EOWf zo!8?D(Vs%ogIs^C^T+8LC?ab(dKLQj1VLsFmZHP!siCHP7@kuTa7XJP6q;&2ASIy$ zD`bzFuxk1<6oe)n5!6jb+-R-ftF2DkQ1!%xRlh^p{3-0rnq>GB z356<+-G59|pB5B;L{);+@dZxMh~t3nMU*r>kwZt@wcmy=(x`n^S^N|#`%V|FLM*bK z2m&$gZr?4oOjK!_I(?uQ9T^=cBzeof4PB9g!C|qKT)ZDdhJv>Ql_qAr^8!PLztYq7 zYdt!9fZ3Px$Yx|fvt)?rbMA=$5BOw`_z#)4;3~lVh7dvsA%qY@2qATB?FBz~##hYf zX1i^v6S80z()Bk-bg} zYd*d^`}dE~yDLG)${*vd#&B`3=l__Yzq-z5+K=5n3_KkY4$_PBJ1=g3QvPN6w=?gP z?OUER+?d~{_SZKu_TJ6mx zP~`RU_=105-=A}J6fS4My85}Sb4q9e0K?;)!2kdN delta 332 zcmeys^nq!DZhf>+vjUGp;PT6JH~d%KIla!{@r8yC{z)9)Yqo|6a2`3di2(r`0@u8* z+Wcs%nBM(zjY5$tZWsP9s9$US!Q4%;#VavNb-z)ILe|oQeevB}quyEc)v$`#U+3m8 z4otRgZ{-RJKVZgww5Ddm-*oAa1#_FK`U81hb=NB`lx;{lH+NnRMsU?&(iF6SAScfT+VnS z$jg@P=lb>5uI#;Y-nCf26;0l}ZqxqVq6KdSN=`nryIs3{kL%G)u0st;-?qPFg$IGb ZbomKWn7?Z6w^<1i^K|udS?83{1OQs&m1+P0 diff --git a/test/snapshots/nanox/test_1to2_warning_finalize/00000.png b/test/snapshots/nanox/test_1to2_warning_finalize/00000.png index d08297ed46739c96729072ae4af65cfdfe409c8a..ce7ada0157f94ddf6a826417b19e0826837c0e7b 100644 GIT binary patch delta 495 zcmVa)lraKy9ZxVgE~FFa2Q3Fd=9}dF1w-FVq-9cqhjJ00000 z00000|AnvB2J{nS%;gZmLQ9_DvI9!jmw4<3e;ts$U%Fd;>4NXo26Q4E?auFBi7}Sz z&-tSZyv_hvMr)XR9R7#j86bS^(e(*`r=Wvl=q7x|MGOD{0Dk~rIQ0#t^Bzzu3L&JI z50B)pD49c_sWHa#m(EZ`2q9}J%b(3F;if!N6OV4fVh9N1)c18)iLa^>RYMv|A{C=f z&2t-!HP&LS_FBmE;Qe5n+PpkV)F4{;qot%25D5Ua+2!oKw82IRNcWtShzK&{3mZvoK?9KH$8~XDBK+{fl;{KQ9Uiy)#!yqQaL=Cs+e0dXsh;Nv?Z2$lO z000000PtV(BAe5Ja5;u#DC)k2w6dxHCZcI-=`$;+=vvj-fB%GcIBP0Dk}g0K=(oFrD{+T2V@A ze|Ymq{)mz}^qHD-mY;NnB2r34i!6UOkA$1bNZq-06IMe&8D~DPyGp$^m6#g#p`=nV z=F~j4!C7N1)@rYZG7p{)#+l74v&0Odr9WCqq<~5Qn9Y{6^V9}sjjb8qG5e+2KUY7# zT9Yc6Z~b~6w|~KuuSfTTs6jKf0}6LG2{{1$POK~S+t5*?U$Zh}Y(C()&EvLibw;@Q z?Es6K%7-Up$~ZEQ5XWz88E2(Rp{Eve*KO_3aq~Z8>C4ftb!gO-He4GUe1G4hv8zBLlWuy-&1N3 zDR{+{0ssI2000000001VYOS?a-`hQTKW%^q)ywHz-$)jK&*#$~n7jMWE|7&}0VrAw z@_N6N@_O0;Cvw8c=>3v$1T>htlX}184ZzQkH2~HkoQ{+Mpnt2bwJ*v-z5vKQPwE&X z3xKub%o~Gb0cfaup1d0&00000>_ED0TrQ-0U+nejW{zq+t=oh{_KQr_MH%TpgQ-qk zp|9`vTfmF1183A;cN2Mo+M^eRA7td1il22B!2}-L_t(|ob8%huEZb+hM7rs()};Vy_^R#hH!C|V_TX0-&1Q9 z6}%vp2mk;8000000002klu}A5v9Ejbe!2k>Of9EVeI=Oz&hxAfLf!4PWynG@1CV8d zyxJ$C*V7FMq8FTu+NX>&pd!?rRQr_I06#-k19+QoI#L>d?|-_UUzCM>2GBlFY8xao zfah`MwLvliR7{^IuOkEi004j;Nax1oLaX;BK2JGwT-->(ntzGEC`4TpkzUwfF4Gnm z82jxC@VdLe5y_Xk-PV2{p2!1j{8@L#%VSD5pFOlW$2-`85BGyt7Mlm&xbFYHp!3|b z|La=Ddo9!*Yp|&9;NN04sHJql5joxvTgBR$t%c7P(OQzhxc~12vwB}xwFjT0x|YCz z3%5jiHuA`Lq0U!c~KL7v#kdt5C zP9Od|nnxMQkM9fBdjSk_!V*Whh2hMFJbw<*hfgnZNq$(g6D}2EMHR7d=0c9|S?(nk ztu*5bnkC`PwQOgAS;U>p)MB#3&vef(L4rWEa%BCP5_l)u8G!uNpDbTUhfZ61N6}fs nnE(I)03HAU000000Dv%mXJomo560as00000NkvXXu0mjf9K`&& diff --git a/test/snapshots/nanox/test_1to2_warning_finalize_1/00002.png b/test/snapshots/nanox/test_1to2_warning_finalize_1/00002.png index e4f32b2869b817b98492d87612f22eb63effb0d4..829345006b378f5327728723b321ceb74c18c7ef 100644 GIT binary patch delta 694 zcmV;n0!jVR1s4QY)KLI@#*kpIcHZQHixZ-Me}$MiAYZk_cdw)IpO4jFqc0*F_11$>r z+T63U1CExDOToUT>%y6F3d%fl{b{XzEvy@_31*)3(y2G1pPz&YA%qY@{wHV~Do!X< z+qKL-FWiQTTfhPDu5JP_YqmFR2q=Jkj`4(=Ge*QMU4&05646_cqB)9snHV-69Kmc&|t-GA04y^ZO3UFSL1;J^4=*)>xfuZ%vd(- zD(f&)M@4X&4IjtbTGDO?d7dCRwrMw zip4X41(eMO78$hB`1VW9}+O+Q)>2Ex%?cOt!P30 z36|1_nptO`et%f0LyWnn!UWWzhbAA9q$tM8WBvZYSvRcHY`+2=aXHDQhugCY%YTX; zP;g@T`RoJs&1(hMa_zIy(ZI7FE;HmHGRueO__Bybk=h5 zF|dI2dbk6h0amslZ4q}$RE9cCwx?i69VIL??O&bo#D7}X*R(dKeYwnYrn}QOns@RL zH$qH5%MDoG^64+su14|pOatDl@eg5gAAlj|uRfhI z=k?9j6vG9&>~_tplR|u(S9O3YF{)qvF=7qUa`f4hVtKf1)*56XkN9=8gY2i1W8a!a zQ>Ij?{!7L>pe#X41yRn~CjMvPXo~FK(8J7*P%>RcEGI*5d(Qy?000000000000000 f00000005Og3xf7hbQa<500000NkvXXu0mjf4Np~) diff --git a/test/snapshots/nanox/test_1to2_warning_finalize_2/00002.png b/test/snapshots/nanox/test_1to2_warning_finalize_2/00002.png index 4ae54ff9811f540b7bfa4ff6498913d0d91110d8..3814bb9c8019a14e6735815461e9271b6eeb6d97 100644 GIT binary patch delta 688 zcmV;h0#E(P1;_=EB!7=dL_t(|ob8)ic7-4eMQK-O;{1o?T>9avW#z>QiqLxY-;EGL z!ZUhHA%qY@2qEO1?EAj&JN_sr|L6FeZ9q9)`EPuh;%l}6E@nK;*|2TfA>X!5l))vl zm^=f7L&a!sjW({*8FoCamqTz^U_9~0Y-*93E)^tMxPM6bUI6G8|fguD~?7%HwO!C9?& zb}Yd4M`s=SPKV}+)68CY`s+vCmuI2Br#oJj1}~-)13{`lSM0l>f(9TOv>7Rrz(&)# zp!)h+n>h436Ms)EEk_hKZ)9dFFqrPOXKG1oSWhzU)OfV<%uQ0~D)d?r)b)G;YA8-; zO{;+3{L&ME*y&;*2qCV#JG!O;^$0Z!&mtXwU}qBrgrvZ|z37x|%=$)d6LY3&IR9UgPA#H-Mi7@OwZNPlg1-HXPeI%Pqe;>4i*XeYS( zCvHdAo4zFgx4)Q6v_AbXaFNt0>oG^iW&k2Gh80(#_t0=MV=xr$Ui78Bms6~NLMN>x z&2)-q10n%au=~%)cSwS>bY2sa3nrx$^n>gGmdZ#6+;Enn=bVLly{x3rPelRr@9{M~TbeVp!hnM$S z4EBKF)s1=P_7a?kTGG$Z3Ae=m1K!LM|BzXh1t~WhLI@#*5JCtcgb+dqA%qY@{ubXX W4xqnDF(@$r0000O7EL`f<);r>VRUGm||6eS6%*$k8E_ZJ3) zEU~toln5b&5JCv~Os?y?t_%OkssDC-?{*-)LiulE+QiRp2dbF)FlR%~`7X~ni#mA8 zE;i2q5l}H3L}<)HVdPcE476ygOP=S586biMj{QChWyEV4eSebudq7&Sspf(d1%2<{ zvois&Coh+RdrjAsk#XwOIdlCEh3`);bB1GpXS%#3?$2CUQG7l|g6Hm+^6W9}?qUrtkiqxl(G;La!1|TW6GjMoLp!-q61J zc7_rVuAagz#360GJG-U><=Cv%f0F(LggY20={O8Vq$6kGu${=L8tM!vu!7(A5Y2KO zat4?q+8@PufOHd`9&=*(tI$Y}YaT8lSWEZ5nwZjihkp^j$@G|14W95(!nh9;6EOWf zo!8?D(Vs%ogIs^C^T+8LC?ab(dKLQj1VLsFmZHP!siCHP7@kuTa7XJP6q;&2ASIy$ zD`bzFuxk1<6oe)n5!6jb+-R-ftF2DkQ1!%xRlh^p{3-0rnq>GB z356<+-G59|pB5B;L{);+@dZxMh~t3nMU*r>kwZt@wcmy=(x`n^S^N|#`%V|FLM*bK z2m&$gZr?4oOjK!_I(?uQ9T^=cBzeof4PB9g!C|qKT)ZDdhJv>Ql_qAr^8!PLztYq7 zYdt!9fZ3Px$Yx|fvt)?rbMA=$5BOw`_z#)4;3~lVh7dvsA%qY@2qAfpB!9F?L_t(|ob8)ia>F1DMQNuy@&1?Oz4XIVhU#r29!c)`vI!Q7 z013%SDF6Tf0001dCg*vc=NbRV=>KwjuU4Q`Q@)K&Z}GEQ0TppR#NBWl$JKru2k8@U zS;gWVKnzND12K)*NQBfrqM^yNyk$OH>;Ph{;M#vCp|!X+qkl759|OvOpn5bE&**Do z&&mm?-@J7Nmrv)NBkR=Yv#0+lrF<mQM62ci!|CV82Ihk)H_{$$Z*Dpy+mr0#;sdlv~P`ZXaLaEYKjBmbaYbEp7(ZTn$%i&WVcje^M{?!wj05_tN z4q|0ABBw=*hy9Y{5V2&VxYo$gXNS~G3votcP)^`-w)lU*C$q&rWM(q0Gz$O#005AV zSVSv3o$lYCHYp_u>T7{SY%!Ps@RaxP{@4Kk000000DK<5@_rcskp-u=00000NkvXX Hu0mjfVt`r! delta 726 zcmV;{0xA9N1?~lqB!9I@L_t(|ob8)ij>8}fMVZm;B>P`d_A(!l5b}!~o@sN>S3`(# zjltMyQzC>ALI@$`ot)=+o+o}Q=>Kv2?p7dWQ+|z2Z}GQV0T**V%++ul$JKruhv|*l@5C#>iL72vD6hd+z)6n8s-LjrXtN>vw(D&OUlot19bblrLV?de^RF8sGGy2}x zvvUISH!rt>Yfsmm5kC$3Jahj^DgA65JKht_IO&B`&!e9ogb5*p5JKKbg}&t6gXV|oLzpN51OlL28|P-O)z^sYWX@8n>&MeU9$|(Kf0=+`MV+AW;m=+;2{Oh zTgVll%@kK9bHUvU%U*5Si<#i0nwVkV1JS{glkaK|sDEl0^_jQj1(Jsh+I(Eb`;Rh? zD`#rJxtkVr%5M-@ePp10N>M+#Y0~bwEC3EmK7Gk!3jtEvf+H8X*s}|fi;9ss2UF4J zZGS0$cXKyWSs`Iyz%Xk>h~#p2ZrJ^2m!#}r+8z1h*!{Tz2qATB?FBz~##hYf zX1i^v6S80z()Bk-bg} zYd*d^`}dE~yDLG)${*vd#&B`3=l__Yzq-z5+K=5n3_KkY4$_PBJ1=g3QvPN6w=?gP z?OUER+?d~{_SZKu_TJ6mx zP~`RU_=105-=A}J6fS4My85}Sb4q9e0K?;)!2kdN delta 332 zcmeys^nq!DZhf>+vjUGp;PT6JH~d%KIla!{@r8yC{z)9)Yqo|6a2`3di2(r`0@u8* z+Wcs%nBM(zjY5$tZWsP9s9$US!Q4%;#VavNb-z)ILe|oQeevB}quyEc)v$`#U+3m8 z4otRgZ{-RJKVZgww5Ddm-*oAa1#_FK`U81hb=NB`lx;{lH+NnRMsU?&(iF6SAScfT+VnS z$jg@P=lb>5uI#;Y-nCf26;0l}ZqxqVq6KdSN=`nryIs3{kL%G)u0st;-?qPFg$IGb ZbomKWn7?Z6w^<1i^K|udS?83{1OQs&m1+P0 diff --git a/test/snapshots/nanox/test_addr_display/00000.png b/test/snapshots/nanox/test_addr_display/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ea3703ddc3e8d5b9b1e0d83d994e85fd5659e057 GIT binary patch literal 686 zcmV;f0#W^mP)ibk@H>1a_`m+a>e z5g?oe&i%d?N{@RZx|8#JKw7Y=UInS<^s{@<$pOeuUM>Z%HC-Dc^E9w|=K7OT`a0Nm zye63Yq_>@VGy3_PFd>8xLI`=|ekU-iwiA@ZzgF$bqis8#}{a^B7q5KQ&k}T zRI=0a9+R(imTn%~cBT(zwU0OkF34G7R!19pAvW~>N$CBPXzw?Cl%Mhn6&%V&8lTcs zQ|`g*apBu%Q|wevRdXY8N^9Qf$vcErjS*FDE(ko-nTN)F_!Ji)Ikn>526}>a%92tT zuC05Rdn)P&?z`}=t098a1t)2&syeiJv^cK{t6JHusvcV(w|kD&d+2#9^;&3f^zM%?1PcT~hvty=t! zsQ~Umcq6mKoMli66af=A$-kEkZ(W*3310k92_S?JLI@#*5JCtcgb+dqA%r}ZUl*%o U?#Jba1poj507*qoM6N<$g6>K^P5=M^ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display/00001.png b/test/snapshots/nanox/test_addr_display/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=YwaunSk|hFqW?7)TH`Jk~9Gerv(6ecqmn7nn8uWB;3b zw{g88mtqOmX|1nQ6UyKSixvS1g}CmE5?ACG-| zpBvCv#x={;%P2FXMyx;J&mSL^`zg=uAmI;8wJYD@< J);T3K0RY{rqSycc literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_unusual_path/00000.png b/test/snapshots/nanox/test_addr_display_unusual_path/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..6ebf2582dda066ab28d4095a45b5b1a1a814312e GIT binary patch literal 500 zcmV#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000}z` z?&-JIox!g;vLOvry@8CZBkwSL9L1fda<$W}qjL@#qs_kU?{~=(wEhj~N%v4Yw#t`z zR~yORJO{g$pkwXC-;sUA?k!h)E7=}^8hg2Oy=-6BX>YXVT{QKc4euALCYkKJQBqCz zoiPV@Vimd*zr%MTy#N3J000000000000000z&8JPE6>4Z7C4vy0000P)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_unusual_path/00004.png b/test/snapshots/nanox/test_addr_display_unusual_path/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..b79de80ccc770decb63e97d35ce1ff63ebf8e4ec GIT binary patch literal 767 zcmVRQCbW-b>6D`{6 zlIyv}4iJ+CuKipO?TmXKy^{53K>5I-x;2#Eq^~`DRyv@LybT3MOxKl>bsE&UXZ$Ip z{9E|!I3}3qq<5TpEBgM2Fd>8xLdbXGrlI0`;^k^_vKX`yiK8hnhz`xWLj8>An&8l4 zn}_O;w*6}p{Are(N}1OxZrBzgAG%KuR0{AWJbGaURo-DOsJptshKGb1D{I{j=iZ^r zozZnz)neOLxRDt#E-`FyvUJ!P>M*@HDs|Gu2Vsx?HV%&g83*VHE{p&l?`;C}iAdW| zxa17T0EZpmIbWX{v&QW031oP=IN5E5>)2f*lWM34e4+%OecjJVGfo0Zq(e$-Y-F?p zaw(=+tu;c&jrObH(DP(!or%V}bdZJyX2&LhMov#0o=uR&B58O1b7&We%C~qUwuex0gGl2T&jNgi>uYC~A8BbXz5V8RyAC734N=uB>3aoJ<=& zk$9ZfnkGmQ$G|G1*5ovd%5*6LH>Mr9E(8r5bATBKv`t7qQ>xXWYB3|;SYEa38FRoC zTjx5djD$O|x5J~?I41w=Xq`5sjRw0~zFK2Meg#TzeFuQyOvq9~o-9s6iQM>GVbbeg zhZmh_ikb;+QVb`McnKkd5JJd%5clv{J9`R`c_)1HTUeUMIN+7DUmoNDlaos79eB0_ xUcfE>Rlym|SBVdTJ76(%03n1BLI@$>$1h1y`Axivo}B;y002ovPDHLkV1gu^V%Y!y literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_addr_display_unusual_path/00005.png b/test/snapshots/nanox/test_addr_display_unusual_path/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=YwaunSk|hFqW?7)TH`Jk~9Gerv(6ecqmn7nn8uWB;3b zw{g88mtqOmX|1nQ6UyKSixvS1g}CmE5?ACG-| zpBvCv#x={;%P2FXMyx;J&mSL^`zg=uAmI;8wJYD@< J);T3K0RY{rqSycc literal 0 HcmV?d00001 diff --git a/test/snapshots/nanox/test_decred_sign_message/00003.png b/test/snapshots/nanox/test_decred_sign_message/00003.png index 9088cece139d94e6aa44cc37a3f242f8a4c18e2d..2fda19b19d7472c1543455e4b24ea5c12b56ca9a 100644 GIT binary patch delta 332 zcmeys^nq!DZhatMvjR^;;^sGMcm8|aN#$2*5p`L1sq9C+zqGImSLuda1_VeDH9XcW zdVXucuYKO0ix-$R{bT=|d$)1DA(vta*J-VTB?FBz~##hYf zX1i^v6S80z()Bk-bg} zYd*d^`}dE~yDLG)${*vd#&B`3=l__Yzq-z5+K=5n3_KkY4$_PBJ1=g3QvPN6w=?gP z?OUER+?d~{_SZKu_TJ6mx zP~`RU_=105-=A}J6fS4My85}Sb4q9e0K?;)!2kdN delta 332 zcmeys^nq!DZhf>+vjUGp;PT6JH~d%KIla!{@r8yC{z)9)Yqo|6a2`3di2(r`0@u8* z+Wcs%nBM(zjY5$tZWsP9s9$US!Q4%;#VavNb-z)ILe|oQeevB}quyEc)v$`#U+3m8 z4otRgZ{-RJKVZgww5Ddm-*oAa1#_FK`U81hb=NB`lx;{lH+NnRMsU?&(iF6SAScfT+VnS z$jg@P=lb>5uI#;Y-nCf26;0l}ZqxqVq6KdSN=`nryIs3{kL%G)u0st;-?qPFg$IGb ZbomKWn7?Z6w^<1i^K|udS?83{1OQs&m1+P0 diff --git a/test/snapshots/stax/test_1to2_get_pubkey/00000.png b/test/snapshots/stax/test_1to2_get_pubkey/00000.png index 32a20c9f042cb2b57600928334d50b8a21421233..ffd9129898cf04120c107e8397875ec0fdf173d3 100644 GIT binary patch literal 8746 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 literal 12646 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 diff --git a/test/snapshots/stax/test_1to2_get_pubkey/00001.png b/test/snapshots/stax/test_1to2_get_pubkey/00001.png index eb3d03546ea699eba540460bdf5773c53568a24e..27f08963160773a254539075331f32c71385355e 100644 GIT binary patch literal 12851 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