Skip to content

Commit

Permalink
Add Stax layouts for generating SSKR shares
Browse files Browse the repository at this point in the history
  • Loading branch information
aido committed Jul 29, 2024
1 parent aa58ae5 commit ec27425
Show file tree
Hide file tree
Showing 14 changed files with 460 additions and 231 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Using Ledger SDK `cx_crc32()` function rather than buggy `cx_crc32_hw()`.
- Fix build with SDK master for Nano S

## [1.7.1] - 2024-03-06
## [1.7.1] - 2024-04-06

### Changed

Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
![nanox](https://img.shields.io/badge/nanox-working-green?logo=data:image/svg%2bxml;base64,PHN2ZyB3aWR0aD0iMTQ3IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDE0NyAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTAgOTEuNjU0OFYxMjhINTUuMjkzVjExOS45NEg4LjA1NjMxVjkxLjY1NDhIMFpNMTM4Ljk0NCA5MS42NTQ4VjExOS45NEg5MS43MDdWMTI3Ljk5OEgxNDdWOTEuNjU0OEgxMzguOTQ0Wk01NS4zNzMzIDM2LjM0NTJWOTEuNjUyOUg5MS43MDdWODQuMzg0Mkg2My40Mjk2VjM2LjM0NTJINTUuMzczM1pNMCAwVjM2LjM0NTJIOC4wNTYzMVY4LjA1ODQ0SDU1LjI5M1YwSDBaTTkxLjcwNyAwVjguMDU4NDRIMTM4Ljk0NFYzNi4zNDUySDE0N1YwSDkxLjcwN1oiIGZpbGw9IndoaXRlIi8+PC9zdmc+)
![nanosp](https://img.shields.io/badge/nanosp-working-green?logo=data:image/svg%2bxml;base64,PHN2ZyB3aWR0aD0iMTQ3IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDE0NyAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTAgOTEuNjU0OFYxMjhINTUuMjkzVjExOS45NEg4LjA1NjMxVjkxLjY1NDhIMFpNMTM4Ljk0NCA5MS42NTQ4VjExOS45NEg5MS43MDdWMTI3Ljk5OEgxNDdWOTEuNjU0OEgxMzguOTQ0Wk01NS4zNzMzIDM2LjM0NTJWOTEuNjUyOUg5MS43MDdWODQuMzg0Mkg2My40Mjk2VjM2LjM0NTJINTUuMzczM1pNMCAwVjM2LjM0NTJIOC4wNTYzMVY4LjA1ODQ0SDU1LjI5M1YwSDBaTTkxLjcwNyAwVjguMDU4NDRIMTM4Ljk0NFYzNi4zNDUySDE0N1YwSDkxLjcwN1oiIGZpbGw9IndoaXRlIi8+PC9zdmc+)
![stax](https://img.shields.io/badge/stax-in_progress-orange?logo=data:image/svg%2bxml;base64,PHN2ZyB3aWR0aD0iMTQ3IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDE0NyAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTAgOTEuNjU0OFYxMjhINTUuMjkzVjExOS45NEg4LjA1NjMxVjkxLjY1NDhIMFpNMTM4Ljk0NCA5MS42NTQ4VjExOS45NEg5MS43MDdWMTI3Ljk5OEgxNDdWOTEuNjU0OEgxMzguOTQ0Wk01NS4zNzMzIDM2LjM0NTJWOTEuNjUyOUg5MS43MDdWODQuMzg0Mkg2My40Mjk2VjM2LjM0NTJINTUuMzczM1pNMCAwVjM2LjM0NTJIOC4wNTYzMVY4LjA1ODQ0SDU1LjI5M1YwSDBaTTkxLjcwNyAwVjguMDU4NDRIMTM4Ljk0NFYzNi4zNDUySDE0N1YwSDkxLjcwN1oiIGZpbGw9IndoaXRlIi8+PC9zdmc+)
![flex](https://img.shields.io/badge/stax-in_progress-orange?logo=data:image/svg%2bxml;base64,PHN2ZyB3aWR0aD0iMTQ3IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDE0NyAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTAgOTEuNjU0OFYxMjhINTUuMjkzVjExOS45NEg4LjA1NjMxVjkxLjY1NDhIMFpNMTM4Ljk0NCA5MS42NTQ4VjExOS45NEg5MS43MDdWMTI3Ljk5OEgxNDdWOTEuNjU0OEgxMzguOTQ0Wk01NS4zNzMzIDM2LjM0NTJWOTEuNjUyOUg5MS43MDdWODQuMzg0Mkg2My40Mjk2VjM2LjM0NTJINTUuMzczM1pNMCAwVjM2LjM0NTJIOC4wNTYzMVY4LjA1ODQ0SDU1LjI5M1YwSDBaTTkxLjcwNyAwVjguMDU4NDRIMTM4Ljk0NFYzNi4zNDUySDE0N1YwSDkxLjcwN1oiIGZpbGw9IndoaXRlIi8+PC9zdmc+)

[![Build app-seed-tool](https://github.com/aido/app-seed-tool/actions/workflows/ci-workflow.yml/badge.svg)](https://github.com/aido/app-seed-tool/actions/workflows/ci-workflow.yml)
[![CodeQL](https://github.com/aido/app-seed-tool/actions/workflows/codeql-workflow.yml/badge.svg)](https://github.com/aido/app-seed-tool/actions/workflows/codeql-workflow.yml)
Expand All @@ -23,13 +24,13 @@ Use the utilities provided by this Ledger application to check a backed up BIP-3
Not all Ledger devices are equal. The older, less capable devices do not have the capacity to provide a full range of seed utilities. The following table lists the seed utilities provided by each devices type:
<div align="center">

||Nano S|Nano S+|Nano X|Stax|
| :--- | :---: | :---: | :---: | :---: |
|[Check BIP39](#check-bip39)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|
|[Check Shamir's secret shares](#check-shamirs-secret-shares)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{orange}✓}$$|
|[Generate Shamir's secret sharing](#generate-shamirs-secret-sharing)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{orange}✓}$$|
|[Recover BIP39](#recover-bip39)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{orange}✓}$$|
|[Generate BIP85](#generate-bip85)|$${\color{red}✗}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|
||Nano S|Nano S+|Nano X|Stax|Flex|
| :--- | :---: | :---: | :---: | :---: | :---: |
|[Check BIP39](#check-bip39)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{orange}✓}$$|
|[Check Shamir's secret shares](#check-shamirs-secret-shares)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|
|[Generate Shamir's secret sharing](#generate-shamirs-secret-sharing)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|
|[Recover BIP39](#recover-bip39)|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{green}✓}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|
|[Generate BIP85](#generate-bip85)|$${\color{red}✗}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|$${\color{orange}✓}$$|
</div>

## Application menu flow
Expand Down
10 changes: 5 additions & 5 deletions src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
#define ONBOARDING_WORD_COMPLETION_MAX_ITEMS 8
#define BOLOS_UX_HASH_LENGTH 4 // as on the blue

#define MAX_WORD_LENGTH 8
#define MAX_NUMBER_LENGTH 2
#define BIP39_MAX_WORD_LENGTH 8
#define MAX_NUMBER_LENGTH 2

enum {
MNEMONIC_SIZE_12 = 12,
MNEMONIC_SIZE_18 = 18,
MNEMONIC_SIZE_24 = 24,
BIP39_MNEMONIC_SIZE_12 = 12,
BIP39_MNEMONIC_SIZE_18 = 18,
BIP39_MNEMONIC_SIZE_24 = 24,
};

// Type of onboarding we are performing (BIP39 or SSKR)
Expand Down
6 changes: 3 additions & 3 deletions src/nano/ui_nano.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ const char* number_of_bip39_words_getter(unsigned int idx) {
void number_of_bip39_words_selector(unsigned int idx) {
switch (idx) {
case 0:
G_bolos_ux_context.onboarding_kind = MNEMONIC_SIZE_12;
G_bolos_ux_context.onboarding_kind = BIP39_MNEMONIC_SIZE_12;
goto word_init;
case 1:
G_bolos_ux_context.onboarding_kind = MNEMONIC_SIZE_18;
G_bolos_ux_context.onboarding_kind = BIP39_MNEMONIC_SIZE_18;
goto word_init;
case 2:
G_bolos_ux_context.onboarding_kind = MNEMONIC_SIZE_24;
G_bolos_ux_context.onboarding_kind = BIP39_MNEMONIC_SIZE_24;
goto word_init;
word_init:
screen_onboarding_bip39_restore_init();
Expand Down
55 changes: 29 additions & 26 deletions src/stax/mnemonic.c → src/stax/bip39_mnemonic.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
#include <string.h>

#include "../ux_common/common_bip39.h"
#include "./mnemonic.h"
#include "./bip39_mnemonic.h"

#if defined(TARGET_STAX)

typedef struct buffer {
typedef struct bip39_buffer_struct {
// the mnemonic passphrase, built over time
char buffer[MAX_MNEMONIC_LENGTH];
char buffer[BIP39_MNEMONIC_MAX_LENGTH];
// current length of the mnemonic passphrase
size_t length;
// index of the current word ((size_t)-1 mean there is no word currently)
size_t current_word_index;
// array of every stored word lengths (used for removing them if needed)
size_t word_lengths[MNEMONIC_SIZE_24];
size_t word_lengths[BIP39_MNEMONIC_SIZE_24];
// expected number of word in the final mnemonic (12 or 18 or 24)
size_t final_size;
} buffer_t;
} bip39_buffer_t;

static buffer_t mnemonic = {0};
static bip39_buffer_t mnemonic = {0};

size_t mnemonic_shrink(const size_t size) {
if (size == 0 || size > mnemonic.length) {
Expand All @@ -28,41 +28,41 @@ size_t mnemonic_shrink(const size_t size) {
} else {
mnemonic.length -= size;
}
memzero(&mnemonic.buffer[mnemonic.length], MAX_MNEMONIC_LENGTH - mnemonic.length);
memzero(&mnemonic.buffer[mnemonic.length], BIP39_MNEMONIC_MAX_LENGTH - mnemonic.length);
return mnemonic.length;
}

void set_mnemonic_final_size(const size_t size) {
void bip39_mnemonic_final_size_set(const size_t size) {
mnemonic.final_size = size;
}

size_t get_mnemonic_final_size() {
size_t bip39_mnemonic_final_size_get(void) {
return mnemonic.final_size;
}

size_t get_current_word_number() {
size_t bip39_mnemonic_current_word_number_get(void) {
return mnemonic.current_word_index + 1;
}

void reset_mnemonic() {
void bip39_mnemonic_reset(void) {
memzero(&mnemonic, sizeof(mnemonic));
mnemonic.current_word_index = (size_t) -1;
}

bool remove_word_from_mnemonic() {
PRINTF("Removing a word, currently there is '%ld' of them\n", mnemonic.current_word_index + 1);
bool bip39_mnemonic_word_remove(void) {
PRINTF("Removing a word, currently there is '%d' of them\n", mnemonic.current_word_index + 1);
if (mnemonic.current_word_index == (size_t) -1) {
return false;
}
const size_t current_length = mnemonic.word_lengths[mnemonic.current_word_index];
mnemonic.current_word_index--;
// removing previous word from mnemonic buffer (+ 1 blank space)
mnemonic_shrink(current_length + 1);
PRINTF("Number of remaining words in the mnemonic: '%ld'\n", mnemonic.current_word_index + 1);
PRINTF("Number of remaining words in the mnemonic: '%d'\n", mnemonic.current_word_index + 1);
return true;
}

size_t add_word_in_mnemonic(const char* const buffer, const size_t size) {
size_t bip39_mnemonic_word_add(const char* const buffer, const size_t size) {
if (mnemonic.current_word_index != (size_t) -1) {
// adding an extra white space ' ' between words
mnemonic.buffer[mnemonic.length++] = ' ';
Expand All @@ -72,35 +72,38 @@ size_t add_word_in_mnemonic(const char* const buffer, const size_t size) {
mnemonic.length += size;
mnemonic.current_word_index++;
mnemonic.word_lengths[mnemonic.current_word_index] = size;
PRINTF("Number of words in the mnemonic: '%ld'\n", get_current_word_number());
PRINTF("Number of words in the mnemonic: '%d'\n", bip39_mnemonic_current_word_number_get());
PRINTF("Current mnemonic: '%s'\n", &mnemonic.buffer[0]);
return get_current_word_number();
return bip39_mnemonic_current_word_number_get();
}

bool is_mnemonic_complete() {
bool bip39_mnemonic_complete_check(void) {
return (mnemonic.final_size == 0
? false
: (mnemonic.current_word_index + 1) >= get_mnemonic_final_size());
: (mnemonic.current_word_index + 1) >= bip39_mnemonic_final_size_get());
}

bool check_mnemonic() {
if (!is_mnemonic_complete()) {
bool bip39_mnemonic_check(void) {
if (!bip39_mnemonic_complete_check()) {
return false;
}
PRINTF("Checking the following mnemonic: '%s' (size %ld)\n",
PRINTF("Checking the following mnemonic: '%s' (size %d)\n",
&mnemonic.buffer[0],
mnemonic.length);
const bool result =
bolos_ux_bip39_mnemonic_check((unsigned char*) &mnemonic.buffer[0], mnemonic.length);
// Don;t clear the mneminic just yet as we may need it to generate SSKR shares
// reset_mnemonic();
// bip39_mnemonic_reset();
return result;
}

#if defined(TEST)
char* get_mnemonic() {
// Used for BIP39 <-> SSKR roundtrip
char* bip39_mnemonic_get(void) {
return mnemonic.buffer;
}
#endif

size_t bip39_mnemonic_length_get(void) {
return mnemonic.length;
}

#endif
34 changes: 20 additions & 14 deletions src/stax/mnemonic.h → src/stax/bip39_mnemonic.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,58 @@

#if defined(TARGET_STAX)

#define memzero(...) explicit_bzero(__VA_ARGS__)
#define MAX_MNEMONIC_LENGTH (MNEMONIC_SIZE_24 * (MAX_WORD_LENGTH + 1))
#define memzero(...) explicit_bzero(__VA_ARGS__)
#define BIP39_MNEMONIC_MAX_LENGTH (BIP39_MNEMONIC_SIZE_24 * (BIP39_MAX_WORD_LENGTH + 1))

/*
* Sets how many words are expected in the mnemonic passphrase
*/
void set_mnemonic_final_size(const size_t size);
void bip39_mnemonic_final_size_set(const size_t size);

/*
* Returns how many words are expected in the mnemonic passphrase
*/
size_t get_mnemonic_final_size(void);
size_t bip39_mnemonic_final_size_get(void);

/*
* Returns how many words are currently stored in the mnemonic
*/
size_t get_current_word_number(void);
size_t bip39_mnemonic_current_word_number_get(void);

/*
* Check if the current number of words in the mnemonic fits the expected number of words
*/
bool is_mnemonic_complete(void);
bool bip39_mnemonic_complete_check(void);

/*
* Check if the currently stored mnemonic generates the same seed as the current device's one
*/
bool check_mnemonic(void);
bool bip39_mnemonic_check(void);

/*
* Erase all information and reset the indexes
*/
void reset_mnemonic(void);
void bip39_mnemonic_reset(void);

/*
* Remove the latest word from the passphrase, returns true if there was at least one to remove,
* else false (there was no word)
*/
bool remove_word_from_mnemonic(void);
bool bip39_mnemonic_word_remove(void);

/*
* Adds a word in the passphrase, returns how many words are stored in the mnemonic
*/
size_t add_word_in_mnemonic(const char* const buffer, const size_t size);
size_t bip39_mnemonic_word_add(const char* const buffer, const size_t size);

#if defined(TEST)
char* get_mnemonic();
#endif
/*
* Returns the mnemonic passphrase
*/
char* bip39_mnemonic_get(void);

/*
* Returns length of the mnemonic passphrase
*/
size_t bip39_mnemonic_length_get(void);

#endif // TARGET_NANOS
#endif // TARGET_STAX
2 changes: 1 addition & 1 deletion src/stax/layout_generic_screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ nbgl_button_t *generic_screen_set_back_button() {
button->obj.area.height = BUTTON_DIAMETER;
button->radius = BUTTON_RADIUS;
button->text = NULL;
button->icon = &C_leftArrow32px;
button->icon = &C_Back_32px;
button->obj.alignmentMarginX = 0;
button->obj.alignmentMarginY = UPPER_MARGIN;
button->obj.alignment = TOP_LEFT;
Expand Down
76 changes: 76 additions & 0 deletions src/stax/sskr_shares.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <os.h>
#include <string.h>

#include "../ux_common/common_sskr.h"
#include "./sskr_shares.h"
#include "./bip39_mnemonic.h"

#if defined(TARGET_STAX)

typedef struct sskr_buffer_struct {
// The SSKR shares, built over time
char buffer[SSKR_SHARES_MAX_LENGTH];
// current length of the shares buffer
unsigned int length;
unsigned int group_descriptor[1][2];
uint8_t count;
} sskr_buffer_t;

static sskr_buffer_t shares = {0};

void sskr_sharenum_set(const uint8_t sharenum) {
shares.group_descriptor[0][1] = sharenum;
}

uint8_t sskr_sharenum_get(void) {
return shares.group_descriptor[0][1];
}

void sskr_threshold_set(const uint8_t threshold) {
shares.group_descriptor[0][0] = threshold;
}

uint8_t sskr_threshold_get(void) {
return shares.group_descriptor[0][0];
}

uint8_t sskr_sharecount_get(void) {
return shares.count;
}

void sskr_shares_reset(void) {
memzero(&shares, sizeof(shares));
}

void sskr_shares_from_bip39_mnemonic(void) {

shares.length = 0;

bolos_ux_bip39_to_sskr_convert((unsigned char*) bip39_mnemonic_get(),
bip39_mnemonic_length_get(),
bip39_mnemonic_final_size_get(),
shares.group_descriptor[0],
&shares.count,
(unsigned char*) shares.buffer,
&shares.length);

if (shares.count > 0) {
PRINTF("SSKR share count is %d\n", shares.count);
PRINTF("SSKR share buffer length is %d\n", shares.length);
for (uint8_t share = 0; share < shares.count; share++) {
PRINTF("SSKR share %d:\n", share + 1);
PRINTF("%.*s\n",
shares.length / shares.count,
shares.buffer + share * shares.length / shares.count);
}
}
}

char* sskr_shares_get(void) {
return shares.buffer;
}

size_t sskr_shares_length_get(void) {
return shares.length;
}
#endif
Loading

0 comments on commit ec27425

Please sign in to comment.