Skip to content

Commit

Permalink
Feat/swap (#131)
Browse files Browse the repository at this point in the history
* update deps

* add swap CI

* add swap support structure

* support swap functions

* update snapshots

* fix build

* small fixes
  • Loading branch information
chcmedeiros authored Dec 20, 2024
1 parent 0f9bcc2 commit 1544e5a
Show file tree
Hide file tree
Showing 220 changed files with 637 additions and 30 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/swap-ci-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Swap functional tests

on:
workflow_dispatch:
push:
pull_request:
branches:
- master
- main
- develop

jobs:
job_functional_tests:
uses: LedgerHQ/app-exchange/.github/workflows/reusable_swap_functional_tests.yml@develop
with:
branch_for_cosmos: ${{ github.ref }}
repo_for_cosmos: ${{ github.repository }}
test_filter: '"ATOM or atom or Cosmos or cosmos"'
24 changes: 21 additions & 3 deletions app/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,18 @@ include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.installer_script
include $(BOLOS_SDK)/Makefile.defines
include $(CURDIR)/Makefile.version

ifndef COIN
COIN=ATOM
endif

PRODUCTION_BUILD ?= 1
ifeq ($(COIN),ATOM)
ifeq ($(TARGET_NAME),TARGET_NANOS)
HAVE_SWAP ?= 0
else
HAVE_SWAP ?= 1
endif
endif

# Display the target name
$(info ************ TARGET_NAME = [$(TARGET_NAME)])
Expand All @@ -38,14 +49,21 @@ ifeq ($(PRODUCTION_BUILD), 1)
else
$(info ************ PRODUCTION_BUILD = [INTERNAL USE])
endif

ifeq ($(HAVE_SWAP), 1)
$(info ************ HAVE_SWAP = [ENABLED])
DEFINES += HAVE_SWAP=$(HAVE_SWAP)
else
$(info ************ HAVE_SWAP = [DISABLED])
endif


# Add the PRODUCTION_BUILD definition to the compiler flags
DEFINES += PRODUCTION_BUILD=$(PRODUCTION_BUILD)

include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.app_testing

ifndef COIN
COIN=ATOM
endif


$(info COIN = [$(COIN)])

Expand Down
4 changes: 2 additions & 2 deletions app/Makefile.version
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This is the `transaction_version` field of `Runtime`
APPVERSION_M=2
# This is the `spec_version` field of `Runtime`
APPVERSION_N=35
APPVERSION_N=36
# This is the patch version of this release
APPVERSION_P=27
APPVERSION_P=0
25 changes: 25 additions & 0 deletions app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@

#include "chain_config.h"

#ifdef HAVE_SWAP
#include "swap.h"
#endif

static const char *msg_error1 = "Expert Mode";
static const char *msg_error2 = "Required";

Expand Down Expand Up @@ -212,6 +216,17 @@ __Z_INLINE void handleSign(volatile uint32_t *flags, volatile uint32_t *tx, uint
THROW(APDU_CODE_DATA_INVALID);
}

#ifdef HAVE_SWAP
if (G_swap_state.called_from_swap && G_swap_state.should_exit && error_msg == NULL) {
// Call app_sign without going through UI display, the UI validation was done in
// Exchange app already
app_sign();
// Go back to Exchange and report our success to display the modal
finalize_exchange_sign_transaction(true);
// Unreachable
}
#endif

CHECK_APP_CANARY()
view_review_init(tx_getItem, tx_getNumItems, app_sign);
view_review_show(REVIEW_TXN);
Expand Down Expand Up @@ -276,6 +291,16 @@ void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
}
FINALLY
{
#ifdef HAVE_SWAP
if (G_swap_state.called_from_swap && G_swap_state.should_exit) {
// Swap checking failed, send reply now and exit, don't wait next cycle
if (sw != 0) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, *tx);
}
// Go back to exchange and report our status
finalize_exchange_sign_transaction(sw == 0);
}
#endif
}
}
END_TRY;
Expand Down
107 changes: 94 additions & 13 deletions app/src/common/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,106 @@

#include <os_io_seproxyhal.h>

__attribute__((section(".boot"))) int
main(void) {
#ifdef HAVE_NBGL
#include "nbgl_use_case.h"
#endif

#ifdef HAVE_SWAP
#include "lib_standard_app/swap_lib_calls.h"
#include "swap.h"
#endif

#ifdef HAVE_SWAP
// Helper to quit the application in a limited THROW context
static void app_exit(void) {
BEGIN_TRY_L(exit) {
TRY_L(exit) {
os_sched_exit(-1);
}
FINALLY_L(exit) {
}
}
END_TRY_L(exit);
}

// Helper to handle the different library commands
static void library_main(libargs_t *args) {
BEGIN_TRY {
TRY {
switch (args->command) {
case SIGN_TRANSACTION: {
// Backup up transaction parameters and wipe BSS to avoid collusion with
// app-exchange BSS data.
bool success = copy_transaction_parameters(args->create_transaction);
if (success) {
// BSS was wiped, we can now init these globals
G_swap_state.called_from_swap = true;
G_swap_state.should_exit = false;

#ifdef HAVE_NBGL
// On Stax, display a modal
nbgl_useCaseSpinner("Signing");
#endif // HAVE_NBGL

view_init();
app_init();
app_main();
}
break;
}
case CHECK_ADDRESS:
handle_check_address(args->check_address);
break;
case GET_PRINTABLE_AMOUNT:
handle_get_printable_amount(args->get_printable_amount);
break;
default:
break;
}
}
CATCH_OTHER(e) {
}
FINALLY {
os_lib_end();
}
}
END_TRY;
}
#endif

__attribute__((section(".boot"))) int main(int arg0) {
// exit critical section
__asm volatile("cpsie i");

view_init();
os_boot();

BEGIN_TRY
{
TRY
if (arg0 != 0) {
#ifdef HAVE_SWAP
// The app has been started in library mode
libargs_t *args = (libargs_t *)arg0;
if (args->id != 0x100) {
// Invalid mode ID
app_exit();
} else {
library_main(args);
}
#endif
} else {
// The app has been launched from the dashboard
// G_swap_state.called_from_swap = false;
BEGIN_TRY
{
app_init();
app_main();
TRY
{
view_init();
app_init();
app_main();
}
CATCH_OTHER(e)
{}
FINALLY
{}
}
CATCH_OTHER(e)
{}
FINALLY
{}
END_TRY;
}
END_TRY;
}
24 changes: 24 additions & 0 deletions app/src/common/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#include <string.h>
#include "zxmacros.h"

#ifdef HAVE_SWAP
#include "swap.h"
#endif

#if defined(TARGET_NANOS2) || defined(TARGET_STAX) || defined(TARGET_FLEX)
#define RAM_BUFFER_SIZE 8192
#define FLASH_BUFFER_SIZE 16384
Expand Down Expand Up @@ -113,6 +117,26 @@ const char *tx_parse(tx_type_e type)
return parser_getErrorDescription(err);
}

#ifdef HAVE_SWAP
// If in swap mode, compare swap tx parameters with stored info.
if (G_swap_state.called_from_swap) {
if (G_swap_state.should_exit == 1) {
// Safety against trying to make the app sign multiple TX
// This panic quit is a failsafe that should never trigger, as the app is supposed to
// exit after the first send when started in swap mode
os_sched_exit(-1);
} else {
// We will quit the app after this transaction, whether it succeeds or fails
G_swap_state.should_exit = 1;
}
err = check_swap_conditions(&ctx_parsed_tx);
CHECK_APP_CANARY()
if (err != parser_ok) {
return parser_getErrorDescription(err);
}
}
#endif

return NULL;
}

Expand Down
43 changes: 38 additions & 5 deletions app/src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ address_encoding_e encoding = BECH32_COSMOS;

#include "cx.h"

static zxerr_t crypto_extractUncompressedPublicKey(uint8_t *pubKey, uint16_t pubKeyLen) {
static zxerr_t crypto_extractUncompressedPublicKey(uint8_t *pubKey, uint16_t pubKeyLen, uint32_t *hdPath_to_use, uint16_t hdPath_to_use_len) {
if (pubKey == NULL || pubKeyLen < PK_LEN_SECP256K1_UNCOMPRESSED) {
return zxerr_invalid_crypto_settings;
}
Expand All @@ -46,8 +46,8 @@ static zxerr_t crypto_extractUncompressedPublicKey(uint8_t *pubKey, uint16_t pub
// Generate keys
CATCH_CXERROR(os_derive_bip32_with_seed_no_throw(HDW_NORMAL,
CX_CURVE_256K1,
hdPath,
HDPATH_LEN_DEFAULT,
hdPath_to_use,
hdPath_to_use_len,
privateKeyData,
NULL,
NULL,
Expand Down Expand Up @@ -155,14 +155,14 @@ zxerr_t crypto_sign(uint8_t *output,
return error;
}

zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrResponseLen) {
zxerr_t crypto_fillAddress_helper(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrResponseLen, uint32_t *hdPath_to_use, uint16_t hdPath_to_use_len) {
if (buffer_len < PK_LEN_SECP256K1 + 50) {
return zxerr_buffer_too_small;
}

// extract pubkey
uint8_t uncompressedPubkey [PK_LEN_SECP256K1_UNCOMPRESSED] = {0};
CHECK_ZXERR(crypto_extractUncompressedPublicKey(uncompressedPubkey, sizeof(uncompressedPubkey)));
CHECK_ZXERR(crypto_extractUncompressedPublicKey(uncompressedPubkey, sizeof(uncompressedPubkey), hdPath_to_use, hdPath_to_use_len));
CHECK_ZXERR(compressPubkey(uncompressedPubkey, sizeof(uncompressedPubkey), buffer, buffer_len));
char *addr = (char *) (buffer + PK_LEN_SECP256K1);

Expand Down Expand Up @@ -193,3 +193,36 @@ zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrR

return zxerr_ok;
}

// fill a crypto address using the global hdpath
zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrResponseLen){
return crypto_fillAddress_helper(buffer, buffer_len, addrResponseLen, hdPath, HDPATH_LEN_DEFAULT);
}

// Fill address using a hd path coming from check_address_parameters_t
zxerr_t crypto_swap_fillAddress(uint32_t *hdPath_swap,
uint8_t hdPathLen_swap,
char *buffer,
uint16_t bufferLen,
uint16_t *addrResponseLen) {
if (bufferLen < 50) {
return zxerr_buffer_too_small;
}

// extract pubkey
uint8_t uncompressedPubkey [PK_LEN_SECP256K1_UNCOMPRESSED] = {0};
uint8_t compressedPubkey [PK_LEN_SECP256K1] = {0};
CHECK_ZXERR(crypto_extractUncompressedPublicKey(uncompressedPubkey, sizeof(uncompressedPubkey), hdPath_swap, hdPathLen_swap));
CHECK_ZXERR(compressPubkey(uncompressedPubkey, sizeof(uncompressedPubkey), compressedPubkey, sizeof(compressedPubkey)));

uint8_t hashed1_pk[CX_SHA256_SIZE] = {0};
cx_hash_sha256(compressedPubkey, PK_LEN_SECP256K1, hashed1_pk, CX_SHA256_SIZE);

uint8_t hashed2_pk[CX_RIPEMD160_SIZE] = {0};
CHECK_CX_OK(cx_ripemd160_hash(hashed1_pk, CX_SHA256_SIZE, hashed2_pk));
// support only cosmos for now we might need to send the hrp as an address parameter
CHECK_ZXERR(bech32EncodeFromBytes(buffer, bufferLen, "cosmos", hashed2_pk, CX_RIPEMD160_SIZE, 1, BECH32_ENCODING_BECH32));

*addrResponseLen = strnlen(buffer, bufferLen);
return zxerr_ok;
}
5 changes: 5 additions & 0 deletions app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t bufferLen, uint16_t *addrRe

zxerr_t crypto_sign(uint8_t *signature, uint16_t signatureMaxlen, uint16_t *signatureLen);

zxerr_t crypto_swap_fillAddress(uint32_t *hdPath_swap,
uint8_t hdPathLen_swap,
char *buffer,
uint16_t bufferLen,
uint16_t *addrResponseLen);
#ifdef __cplusplus
}
#endif
Loading

0 comments on commit 1544e5a

Please sign in to comment.