Skip to content

Commit 2af5061

Browse files
committed
feat: Address stellar review feedback
1 parent f35100d commit 2af5061

File tree

10 files changed

+349
-471
lines changed

10 files changed

+349
-471
lines changed

apps/stellar_app/stellar_context.h

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@
3131
#define STELLAR_SECRET_KEY_LENGTH 57
3232
#define STELLAR_SIGNATURE_SIZE 64
3333

34+
// Stellar XDR constants
35+
#define STELLAR_ENVELOPE_TYPE_TX 2
36+
#define STELLAR_KEY_TYPE_ED25519 0
37+
#define STELLAR_ASSET_TYPE_NATIVE 0
38+
3439
// Network passphrases
35-
// See
36-
// https://developers.stellar.org/docs/learn/fundamentals/networks
40+
// See https://developers.stellar.org/docs/learn/fundamentals/networks
3741
#define TESTNET_PASSPHRASE "Test SDF Network ; September 2015"
3842
#define MAINNET_PASSPHRASE "Public Global Stellar Network ; September 2015"
3943

@@ -46,28 +50,35 @@ typedef struct {
4650
} stellar_config_t;
4751

4852
// Stellar Memo types
49-
// See
50-
// https://developers.stellar.org/docs/learn/encyclopedia/transactions-specialized/memos
53+
// See https://developers.stellar.org/docs/learn/encyclopedia/transactions-specialized/memos
5154
typedef enum {
52-
MEMO_NONE = 0,
53-
MEMO_TEXT = 1,
54-
MEMO_ID = 2,
55-
MEMO_HASH = 3,
56-
MEMO_RETURN = 4
55+
STELLAR_MEMO_NONE = 0,
56+
STELLAR_MEMO_TEXT = 1,
57+
STELLAR_MEMO_ID = 2,
58+
STELLAR_MEMO_HASH = 3,
59+
STELLAR_MEMO_RETURN = 4
5760
} stellar_memo_type_t;
5861

62+
// Stellar operation types
63+
// See https://developers.stellar.org/docs/learn/fundamentals/transactions/list-of-operations
64+
typedef enum {
65+
STELLAR_OPERATION_CREATE_ACCOUNT = 0,
66+
STELLAR_OPERATION_PAYMENT = 1
67+
} stellar_operation_type_t;
68+
5969
// Stellar transaction structures
70+
// See https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr
6071
typedef struct {
6172
uint8_t source_account[32];
6273
uint64_t sequence_number;
6374
uint32_t fee;
6475
uint32_t operation_count;
65-
uint32_t operation_type; // CREATE_ACCOUNT = 0, PAYMENT = 1
76+
stellar_operation_type_t operation_type;
6677
stellar_memo_type_t memo_type;
6778
union {
68-
char text[29]; // MEMO_TEXT (max 28 bytes + 1 byte delimiter)
69-
uint64_t id; // MEMO_ID
70-
uint8_t hash[32]; // MEMO_HASH or MEMO_RETURN(32 bytes)
79+
char text[29]; // STELLAR_MEMO_TEXT (max 28 bytes + 1 byte delimiter)
80+
uint64_t id; // STELLAR_MEMO_ID
81+
uint8_t hash[32]; // STELLAR_MEMO_HASH or STELLAR_MEMO_RETURN(32 bytes)
7182
} memo;
7283
} stellar_transaction_t;
7384

@@ -88,20 +99,5 @@ typedef enum {
8899
/*****************************************************************************
89100
* GLOBAL FUNCTION PROTOTYPES
90101
*****************************************************************************/
91-
/**
92-
* @brief Generates a Stellar address from a public key
93-
* @details Follows the Stellar address generation algorithm:
94-
* 1. Creates a payload with account ID type (0x30) and the public key
95-
* 2. Calculates CRC16 checksum
96-
* 3. Encodes the result using base32
97-
* See
98-
* https://developers.stellar.org/docs/fundamentals-and-concepts/stellar-data-structures/accounts
99-
*
100-
* @param public_key The 32-byte ED25519 public key
101-
* @param address Buffer to store the resulting address (must be at least
102-
* STELLAR_ADDRESS_LENGTH bytes)
103-
* @return true if the address was generated successfully, false otherwise
104-
*/
105-
bool stellar_generate_address(const uint8_t *public_key, char *address);
106102

107103
#endif /* STELLAR_CONTEXT_H */

apps/stellar_app/stellar_helpers.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262

6363
#include "stellar_helpers.h"
6464

65+
#include "base32.h"
66+
#include "stellar_context.h"
67+
6568
/*****************************************************************************
6669
* EXTERN VARIABLES
6770
*****************************************************************************/
@@ -78,6 +81,14 @@
7881
* STATIC FUNCTION PROTOTYPES
7982
*****************************************************************************/
8083

84+
/**
85+
* @brief Calculate CRC16 checksum for Stellar address encoding
86+
* @param data Input data buffer
87+
* @param len Length of input data
88+
* @return CRC16 checksum
89+
*/
90+
static uint16_t crc16(const uint8_t *data, size_t len);
91+
8192
/*****************************************************************************
8293
* STATIC VARIABLES
8394
*****************************************************************************/
@@ -90,6 +101,20 @@
90101
* STATIC FUNCTIONS
91102
*****************************************************************************/
92103

104+
static uint16_t crc16(const uint8_t *data, size_t len) {
105+
uint16_t crc = 0x0000;
106+
for (size_t i = 0; i < len; i++) {
107+
crc ^= data[i] << 8;
108+
for (int j = 0; j < 8; j++) {
109+
if (crc & 0x8000)
110+
crc = (crc << 1) ^ 0x1021;
111+
else
112+
crc <<= 1;
113+
}
114+
}
115+
return crc;
116+
}
117+
93118
/*****************************************************************************
94119
* GLOBAL FUNCTIONS
95120
*****************************************************************************/
@@ -108,3 +133,25 @@ bool stellar_derivation_path_guard(const uint32_t *path, uint8_t levels) {
108133

109134
return status;
110135
}
136+
137+
bool stellar_generate_address(const uint8_t *public_key, char *address) {
138+
if (!public_key || !address) {
139+
return false;
140+
}
141+
142+
// Stellar address encoding (StrKey format)
143+
// See https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
144+
uint8_t payload[35];
145+
payload[0] = 0x30; // Account ID version byte (6 << 3 | 0 = STRKEY_PUBKEY OR STRKEY_ALG_ED25519)
146+
memcpy(payload + 1, public_key, STELLAR_PUBKEY_RAW_SIZE);
147+
148+
// CRC16-XModem checksum calculation
149+
// See https://stellar.stackexchange.com/questions/255/which-cryptographic-algorithm-is-used-to-generate-the-secret-and-public-keys
150+
uint16_t checksum = crc16(payload, 33);
151+
payload[33] = checksum & 0xFF;
152+
payload[34] = checksum >> 8;
153+
154+
// RFC4648 base32 encoding without padding
155+
base32_encode(payload, 35, address, STELLAR_ADDRESS_LENGTH, BASE32_ALPHABET_RFC4648);
156+
return true;
157+
}

apps/stellar_app/stellar_helpers.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,19 @@
6060
*/
6161
bool stellar_derivation_path_guard(const uint32_t *path, uint8_t levels);
6262

63+
/**
64+
* @brief Generates a Stellar address from a public key
65+
* @details Follows the Stellar address generation algorithm:
66+
* 1. Creates a payload with account ID type (0x30) and the public key
67+
* 2. Calculates CRC16 checksum
68+
* 3. Encodes the result using base32
69+
* See https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
70+
*
71+
* @param public_key The 32-byte ED25519 public key
72+
* @param address Buffer to store the resulting address (must be at least
73+
* STELLAR_ADDRESS_LENGTH bytes)
74+
* @return true if the address was generated successfully, false otherwise
75+
*/
76+
bool stellar_generate_address(const uint8_t *public_key, char *address);
77+
6378
#endif // STELLAR_HELPERS_H

apps/stellar_app/stellar_pub_key.c

Lines changed: 10 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ static bool get_user_consent(const pb_size_t which_request,
219219
*****************************************************************************/
220220
static bool sign_address = false;
221221

222+
/*****************************************************************************
223+
* STATIC FUNCTIONS
224+
*****************************************************************************/
225+
222226
static bool check_which_request(const stellar_query_t *query,
223227
pb_size_t which_request) {
224228
if (which_request != query->get_public_keys.which_request) {
@@ -299,24 +303,13 @@ static bool get_public_key(const uint8_t *seed,
299303
uint8_t *public_key) {
300304
HDNode node = {0};
301305

302-
// Initialize the HDNode with the seed
303-
if (hdnode_from_seed(seed, 64, "ed25519", &node) != 1) {
306+
// Use derive_hdnode_from_path instead of manual derivation
307+
if (!derive_hdnode_from_path(path, path_length, ED25519_NAME, seed, &node)) {
304308
stellar_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 1);
305309
memzero(&node, sizeof(HDNode));
306310
return false;
307311
}
308312

309-
// Derive HDNode from path
310-
for (uint32_t i = 0; i < path_length; i++) {
311-
if (hdnode_private_ckd(&node, path[i]) != 1) {
312-
stellar_send_error(ERROR_COMMON_ERROR_UNKNOWN_ERROR_TAG, 1);
313-
memzero(&node, sizeof(HDNode));
314-
return false;
315-
}
316-
}
317-
318-
hdnode_fill_public_key(&node);
319-
320313
if (NULL != public_key) {
321314
// skip first byte, use raw 32 bytes
322315
memcpy(public_key, node.public_key + 1, STELLAR_PUBKEY_RAW_SIZE);
@@ -342,20 +335,6 @@ static bool fill_public_keys(
342335
return true;
343336
}
344337

345-
static uint16_t crc16(const uint8_t *data, size_t len) {
346-
uint16_t crc = 0x0000;
347-
for (size_t i = 0; i < len; i++) {
348-
crc ^= data[i] << 8;
349-
for (int j = 0; j < 8; j++) {
350-
if (crc & 0x8000)
351-
crc = (crc << 1) ^ 0x1021;
352-
else
353-
crc <<= 1;
354-
}
355-
}
356-
return crc;
357-
}
358-
359338
static bool send_public_keys(
360339
stellar_query_t *query,
361340
const uint8_t pubkey_list[][STELLAR_PUBKEY_RAW_SIZE],
@@ -399,38 +378,10 @@ static bool send_public_keys(
399378
* GLOBAL VARIABLES
400379
*****************************************************************************/
401380

402-
/*****************************************************************************
403-
* STATIC FUNCTIONS
404-
*****************************************************************************/
405-
406381
/*****************************************************************************
407382
* GLOBAL FUNCTIONS
408383
*****************************************************************************/
409384

410-
bool stellar_generate_address(const uint8_t *public_key, char *address) {
411-
if (!public_key || !address) {
412-
return false;
413-
}
414-
415-
// Stellar address encoding (StrKey format)
416-
// See
417-
// https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
418-
uint8_t payload[35];
419-
payload[0] = 6 << 3; // Account ID version byte (0x30)
420-
memcpy(payload + 1, public_key, 32);
421-
422-
// CRC16-XModem checksum calculation
423-
// See
424-
// https://stellar.stackexchange.com/questions/255/which-cryptographic-algorithm-is-used-to-generate-the-secret-and-public-keys
425-
uint16_t checksum = crc16(payload, 33);
426-
payload[33] = checksum & 0xFF;
427-
payload[34] = checksum >> 8;
428-
429-
// RFC4648 base32 encoding without padding
430-
base32_encode(payload, 35, address, 57, BASE32_ALPHABET_RFC4648);
431-
return true;
432-
}
433-
434385
void stellar_get_pub_keys(stellar_query_t *query) {
435386
char wallet_name[NAME_SIZE] = "";
436387
uint8_t seed[64] = {0};
@@ -489,6 +440,9 @@ void stellar_get_pub_keys(stellar_query_t *query) {
489440
if (!stellar_generate_address(pubkey_list[0], address)) {
490441
return;
491442
}
443+
if (sign_address) {
444+
exchange_sign_address(address, sizeof(address));
445+
}
492446
if (!core_scroll_page(ui_text_receive_on, address, stellar_send_error)) {
493447
return;
494448
}
@@ -502,4 +456,4 @@ void stellar_get_pub_keys(stellar_query_t *query) {
502456
}
503457

504458
delay_scr_init(ui_text_check_cysync_app, DELAY_TIME);
505-
}
459+
}

0 commit comments

Comments
 (0)