Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/swap #131

Merged
merged 7 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading