Skip to content
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
4 changes: 2 additions & 2 deletions app/Makefile.version
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Major
APPVERSION_M=1
# Minor
APPVERSION_N=1
APPVERSION_N=2
# Patch
APPVERSION_P=7
APPVERSION_P=0
58 changes: 53 additions & 5 deletions app/src/addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,32 @@
// Use to hold the addr_ui object, used by rust to display the address
uint8_t addr_ui_obj[ADDR_UI_MAX_SIZE] = {0};


zxerr_t app_fill_ed25519_address(uint8_t *buffer, uint16_t buffer_len, uint16_t *addr_len) {
return crypto_fill_ed25519_address(buffer, buffer_len, addr_len);
}

zxerr_t fill_address(
uint32_t *flags,
uint32_t *tx,
uint32_t rx,
uint8_t *buffer,
uint16_t buffer_len
uint16_t buffer_len,
uint8_t curve_type
) {

zemu_log("fill_address\n");

zxerr_t err = _app_fill_address(tx, rx, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE, addr_ui_obj, ADDR_UI_MAX_SIZE);
zxerr_t err = zxerr_ok;
if (curve_type == CURVE_ED25519) {
err = app_fill_ed25519_address(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE -2, &action_addrResponseLen);
*tx = action_addrResponseLen;
} else {
err = _app_fill_address(tx, rx, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE, addr_ui_obj, ADDR_UI_MAX_SIZE);
action_addrResponseLen = *tx;
}

if (err != zxerr_ok)
action_addrResponseLen = 0;

action_addrResponseLen = *tx;
return err;
}

Expand All @@ -68,3 +76,43 @@ zxerr_t addr_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *
uint8_t *pageCount) {
return _addr_get_item(addr_ui_obj, displayIdx, (uint8_t*)outKey, outKeyLen, (uint8_t*)outVal, outValLen, pageIdx, pageCount);
}

zxerr_t addr_getNumItemsEd25519(uint8_t *num_items) {
zemu_log_stack("addr_getNumItems");
*num_items = 1;
if (app_mode_expert()) {
*num_items = 2;
}
return zxerr_ok;
}

zxerr_t addr_getItemEd25519(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen, uint8_t pageIdx,
uint8_t *pageCount) {
ZEMU_LOGF(50, "[addr_getItem] %d/%d\n", displayIdx, pageIdx)

switch (displayIdx) {
case 0:
snprintf(outKey, outKeyLen, "Address");

char buf[80] = {0};
array_to_hexstr(buf, sizeof(buf), G_io_apdu_buffer + 1 + PK_LEN_ED25519, ADDRESS_BUFFER_LEN + ADDRESS_CHECKSUM_LEN);
pageString(outVal, outValLen, buf, pageIdx, pageCount);
return zxerr_ok;
case 1: {
if (!app_mode_expert()) {
return zxerr_no_data;
}

snprintf(outKey, outKeyLen, "Your Path");
char buffer[300];
bip32_to_str(buffer, sizeof(buffer), hdPath, hdPath_len);
pageString(outVal, outValLen, buffer, pageIdx, pageCount);
return zxerr_ok;
}
default:
return zxerr_no_data;
}

}


8 changes: 7 additions & 1 deletion app/src/addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ zxerr_t fill_address(
uint32_t *tx,
uint32_t rx,
uint8_t *buffer,
uint16_t buffer_len
uint16_t buffer_len,
uint8_t curve_type
);

// Return the number of items in the address view
Expand All @@ -36,6 +37,11 @@ zxerr_t addr_getNumItems(uint8_t *num_items);
zxerr_t addr_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outValue, uint16_t outValueLen,
uint8_t pageIdx, uint8_t *pageCount);

zxerr_t addr_getNumItemsEd25519(uint8_t *num_items);

zxerr_t addr_getItemEd25519(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen, uint8_t pageIdx,
uint8_t *pageCount);

#ifdef __cplusplus
}
#endif
52 changes: 49 additions & 3 deletions app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,28 @@ void extractHDPath(uint32_t rx, uint32_t offset) {
_set_root_path(&G_io_apdu_buffer[offset], len_bytes + 1);
}

void extractHDPathEd25519(uint32_t rx, uint32_t offset) {
MEMZERO(hdPath, sizeof(hdPath));

hdPath_len = G_io_apdu_buffer[offset];
offset += 1;

if (hdPath_len > HDPATH_LEN_DEFAULT || (rx - offset) != sizeof(uint32_t) * hdPath_len) {
THROW(APDU_CODE_WRONG_LENGTH);
}

memcpy(hdPath, G_io_apdu_buffer + offset, sizeof(uint32_t) * hdPath_len);

// Convert each hdPath element to big-endian
for (uint8_t i = 0; i < hdPath_len; i++) {
uint32_t value = hdPath[i];
hdPath[i] = ((value & 0xFF000000) >> 24) |
((value & 0x00FF0000) >> 8) |
((value & 0x0000FF00) << 8) |
((value & 0x000000FF) << 24);
}
}

__Z_INLINE bool process_chunk(__Z_UNUSED volatile uint32_t *tx, uint32_t rx) {
if (rx < OFFSET_DATA) {
THROW(APDU_CODE_WRONG_LENGTH);
Expand Down Expand Up @@ -138,13 +160,35 @@ __Z_INLINE void handleGetAddr(volatile uint32_t *flags, volatile uint32_t *tx, u
zemu_log("handleGetAddr\n");

const uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1];
zxerr_t zxerr = fill_address((uint32_t *)flags, (uint32_t*)tx, rx, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE);
const uint8_t curve_type = G_io_apdu_buffer[OFFSET_P2];

if (curve_type != CURVE_SECP256K1 && curve_type != CURVE_ED25519) {
THROW(APDU_CODE_CONDITIONS_NOT_SATISFIED);
}

if (curve_type == CURVE_ED25519) {
extractHDPathEd25519(rx, OFFSET_DATA);
}

zxerr_t zxerr = fill_address((uint32_t *)flags, (uint32_t*)tx, rx, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE, curve_type);
if (zxerr != zxerr_ok) {
*tx = 0;
THROW(APDU_CODE_DATA_INVALID);
}

if (requireConfirmation) {
view_review_init(addr_getItem, addr_getNumItems, app_reply_address);
switch (curve_type) {
case CURVE_ED25519:
view_review_init(addr_getItemEd25519, addr_getNumItemsEd25519, app_reply_address);
break;
case CURVE_SECP256K1:
view_review_init(addr_getItem, addr_getNumItems, app_reply_address);
break;
default:
zemu_log("No match for address kind!\n");
THROW(APDU_CODE_CONDITIONS_NOT_SATISFIED);
break;
}
view_review_show(REVIEW_ADDRESS);
*flags |= IO_ASYNCH_REPLY;
return;
Expand Down Expand Up @@ -225,8 +269,10 @@ __Z_INLINE void handleSignAvaxHash(volatile uint32_t *flags, volatile uint32_t *
// in this case we just received a path suffix
// we are supposed to use the previously stored
// root_path and hash
uint8_t curve_type = G_io_apdu_buffer[OFFSET_P2];

if (G_io_apdu_buffer[OFFSET_P1] != FIRST_MESSAGE) {
app_sign_hash();
app_sign_hash(curve_type);
} else {
// this is the sign_hash transaction
// we received in one go the root path
Expand Down
8 changes: 8 additions & 0 deletions app/src/coin.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ extern "C" {
#define P2_NO_CHAINCODE 0x00
#define P2_CHAINCODE 0x01

#define CURVE_SECP256K1 0x00
#define CURVE_ED25519 0x01
#define PK_LEN_ED25519 32
#define ED25519_AUTH_ID 0x00
#define HASH_LEN 32
#define ADDRESS_BUFFER_LEN 33 // 1 byte auth_id + 32 bytes hash
#define ADDRESS_CHECKSUM_LEN 4

#ifdef __cplusplus
}
#endif
13 changes: 9 additions & 4 deletions app/src/common/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ __Z_INLINE void clean_up_hash_globals() {
_clean_up_hash();
}

__Z_INLINE void app_sign_hash() {
__Z_INLINE void app_sign_hash(uint8_t curve_type) {
zemu_log("app_sign_hash\n");

uint32_t path[HDPATH_LEN_DEFAULT] = {0};
Expand Down Expand Up @@ -73,7 +73,7 @@ __Z_INLINE void app_sign_hash() {
return;
}

err = crypto_sign_avax(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, hash, CX_SHA256_SIZE, path, HDPATH_LEN_DEFAULT);
err = crypto_sign_avax(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, hash, CX_SHA256_SIZE, path, HDPATH_LEN_DEFAULT, curve_type);

if (err != zxerr_ok) {
set_code(G_io_apdu_buffer, 0, APDU_CODE_EXECUTION_ERROR);
Expand All @@ -83,8 +83,13 @@ __Z_INLINE void app_sign_hash() {
if (G_io_apdu_buffer[OFFSET_P1] == LAST_MESSAGE)
clean_up_hash_globals();

set_code(G_io_apdu_buffer, SECP256K1_PK_LEN, APDU_CODE_OK);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, SECP256K1_PK_LEN + 2);
if (curve_type == CURVE_ED25519) {
set_code(G_io_apdu_buffer, ED25519_SIGNATURE_SIZE, APDU_CODE_OK);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, ED25519_SIGNATURE_SIZE + 2);
} else {
set_code(G_io_apdu_buffer, SECP256K1_PK_LEN, APDU_CODE_OK);
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, SECP256K1_PK_LEN + 2);
}
}

}
Expand Down
99 changes: 90 additions & 9 deletions app/src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ zxerr_t crypto_extractPublicKey(uint8_t *pubKey, uint16_t pubKeyLen) {
CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, 32, &cx_privateKey));
CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_Ed25519, NULL, 0, &cx_publicKey));
CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_Ed25519, &cx_publicKey, &cx_privateKey, 1));

for (unsigned int i = 0; i < PK_LEN_25519; i++) {
pubKey[i] = cx_publicKey.W[64 - i];
}

if ((cx_publicKey.W[PK_LEN_25519] & 1) != 0) {
pubKey[31] |= 0x80;
}

error = zxerr_ok;

catch_cx_error:
Expand All @@ -70,6 +72,85 @@ zxerr_t crypto_extractPublicKey(uint8_t *pubKey, uint16_t pubKeyLen) {
return error;
}

zxerr_t crypto_fill_ed25519_address(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrLen) {
if (buffer_len < PK_LEN_ED25519 + 50) {
return zxerr_buffer_too_small;
}
MEMZERO(buffer, buffer_len);
buffer[0] = PK_LEN_ED25519;
CHECK_ZXERR(crypto_extractPublicKey(buffer + 1, buffer_len))

// Create temporary buffer for address construction
uint8_t addr_buffer[ADDRESS_BUFFER_LEN] = {0};
uint8_t hash[HASH_LEN] = {0};

// First byte is ED25519_AUTH_ID (assuming it's defined somewhere, typically 0x01)
addr_buffer[0] = ED25519_AUTH_ID;

// Calculate SHA256 of public key
cx_sha256_t ctx;
MEMZERO(&ctx, sizeof(ctx));
cx_sha256_init_no_throw(&ctx);
CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, buffer + 1, PK_LEN_ED25519, hash, HASH_LEN));

// Copy hash after auth ID
MEMCPY(addr_buffer + 1, hash, HASH_LEN);

// Calculate checksum (SHA256 of the address bytes)
cx_sha256_init_no_throw(&ctx);
CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, addr_buffer, ADDRESS_BUFFER_LEN, hash, HASH_LEN));

// Copy address bytes to output buffer
MEMCPY(buffer + 1 + PK_LEN_ED25519, addr_buffer, ADDRESS_BUFFER_LEN);
// Append checksum (last 4 bytes of hash)
MEMCPY(buffer + 1 + PK_LEN_ED25519 + ADDRESS_BUFFER_LEN, hash + 28, ADDRESS_CHECKSUM_LEN);

*addrLen = 1 + PK_LEN_ED25519 + ADDRESS_BUFFER_LEN + ADDRESS_CHECKSUM_LEN;

return zxerr_ok;
}

zxerr_t crypto_sign_avax_ed25519(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, const uint32_t *path, uint16_t path_len) {
zemu_log_stack("crypto_sign_avax_ed25519");
if (buffer == NULL || message == NULL ||
signatureMaxlen < ED25519_SIGNATURE_SIZE || messageLen != CX_SHA256_SIZE) {
return zxerr_unknown;
}

cx_ecfp_private_key_t cx_privateKey;
uint8_t privateKeyData[64] = {0};

zxerr_t error = zxerr_unknown;

CATCH_CXERROR(os_derive_bip32_with_seed_no_throw(HDW_NORMAL,
CX_CURVE_Ed25519,
path,
path_len,
privateKeyData,
NULL,
NULL,
0));

CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, 32, &cx_privateKey));
CATCH_CXERROR(cx_eddsa_sign_no_throw(&cx_privateKey,
CX_SHA512,
message,
messageLen,
buffer,
signatureMaxlen));

error = zxerr_ok;

catch_cx_error:
MEMZERO(&cx_privateKey, sizeof(cx_privateKey));
MEMZERO(privateKeyData, sizeof(privateKeyData));

if (error != zxerr_ok) {
MEMZERO(buffer, signatureMaxlen);
}

return error;
}

typedef struct {
uint8_t r[32];
Expand All @@ -78,7 +159,7 @@ typedef struct {
} __attribute__((packed)) signature_t;


zxerr_t crypto_sign_avax(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, const uint32_t *path, uint16_t path_len) {
zxerr_t crypto_sign_avax_secp256k1(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, const uint32_t *path, uint16_t path_len) {
if (signatureMaxlen < sizeof(signature_t)) {
return zxerr_buffer_too_small;
}
Expand Down Expand Up @@ -135,13 +216,13 @@ zxerr_t crypto_sign_avax(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_
return zxerr;
}

zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t bufferLen, uint16_t *addrResponseLen) {
if (buffer == NULL || addrResponseLen == NULL) {
return zxerr_unknown;
zxerr_t crypto_sign_avax(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, const uint32_t *path, uint16_t path_len, uint8_t curve_type) {
switch (curve_type) {
case CURVE_SECP256K1:
return crypto_sign_avax_secp256k1(buffer, signatureMaxlen, message, messageLen, path, path_len);
case CURVE_ED25519:
return crypto_sign_avax_ed25519(buffer, signatureMaxlen, message, messageLen, path, path_len);
default:
return zxerr_unknown;
}

// MEMZERO(buffer, bufferLen);
*addrResponseLen = 3 * KEY_LENGTH;

return zxerr_ok;
}
7 changes: 2 additions & 5 deletions app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,8 @@ extern "C" {
extern uint32_t hdPath[HDPATH_LEN_DEFAULT];
extern uint32_t hdPath_len;

zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t bufferLen, uint16_t *addrResponseLen);

zxerr_t crypto_sign_avax(uint8_t *signature, uint16_t signatureMaxlen, const uint8_t *hash, uint16_t hash_len, const uint32_t *path, uint16_t path_len);


zxerr_t crypto_sign_avax(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, const uint32_t *path, uint16_t path_len, uint8_t curve_type);
zxerr_t crypto_fill_ed25519_address(uint8_t *buffer, uint16_t buffer_len, uint16_t *addrLen);

#ifdef __cplusplus
}
Expand Down
Loading
Loading