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

Allow fixing invalid bip39 mnemonic #58

Closed
Closed
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
13 changes: 8 additions & 5 deletions scripts/install-lethekit
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/bin/bash

# Terminal colors
RED=`tput setaf 1`
RESET=`tput sgr0`

git submodule update --init --recursive

# usage: install-lethkit <lethkit-root> <arduino-sketchbook>
Expand All @@ -24,7 +28,7 @@ while (( "$#" )); do
break
;;
-*|--*=) # unsupported flags
echo "Error: Unsupported flag $1" >&2
echo "${RED}==Error: Unsupported flag $1 ==${RESET}" >&2
exit 1
;;
*) # preserve positional arguments
Expand All @@ -36,7 +40,7 @@ done

if [ ${#args[@]} -ne 1 ]
then
usage_error "must be 1 argument"
usage_error "${RED}== Error: must be 1 argument==${RESET}"
fi

echo "Note: Arduino sketchbook location is set in Arduino IDE: click File->Preferences"
Expand Down Expand Up @@ -72,7 +76,7 @@ libpath="${aroot}/libraries"
# We need python to create libwally for arduino
if ! python3 --version -v COMMAND &> /dev/null
then
echo "Please, install python3."
echo "${RED}== Error: Please, install python3.==${RESET}"
exit
fi

Expand All @@ -91,8 +95,7 @@ popd
# First, check if GxEPD2 is already installed (as a directory), warn
# and stop in this case.
gxepd2_path="${aroot}/libraries/GxEPD2"
[ -d ${gxepd2_path} ] && ! [ -L ${gxepd2_path} ] && echo "GxEPD2 already installed in ${libpath}. Please remove it; we need to replace with SW SPI enabled version." && exit 1

[ -d ${gxepd2_path} ] && ! [ -L ${gxepd2_path} ] && echo "${RED}== ERROR: GxEPD2 already installed in ${libpath}. Please remove it and re-run the last command==${RESET}" && exit 1
declare -a libs=(
ArduinoSTL
bc-ur-arduino
Expand Down
4 changes: 4 additions & 0 deletions seedtool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ shares.

![BIP-39 Restore](doc/images/bip39-restore.png)

When restoring BIP39 you can enter invalid BIP39 mnemonic sentence and have it fixed by LetheKit.

![bad checkusm](doc/images/bip39_bad_checksum.png)

### SSKR Recovery

If you possess enough shares of a SSKR set, you can recover the
Expand Down
Binary file added seedtool/doc/images/bip39_bad_checksum.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions seedtool/seed.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class BIP39Seq {
// Returns NULL if restore fails (bad BIP39 checksum).
Seed * restore_seed() const;

// fix_bip39_checksum is only intended for when user wants
// to generate seed from bip39 words
void fix_bip39_checksum(void) { bip39_append_checksum(ctx); }

// we need to have full menmonic words saved as string
// which is needed to calculate mnemonic seed
String get_mnemonic_as_string();
Expand Down
12 changes: 3 additions & 9 deletions seedtool/seed.ino
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,6 @@ uint8_t const * SSKRShareSeq::get_share(size_t ndx) const {
}

void SSKRShareSeq::set_share(size_t ndx, uint8_t const * share, size_t len) {
Serial.println("** **");
Serial.println(ndx); Serial.println(nshares);
serial_assert(ndx < nshares);
if (shares[ndx])
free(shares[ndx]);
Expand All @@ -177,10 +175,6 @@ String SSKRShareSeq::get_share_strings(size_t ndx) const {
Seed * SSKRShareSeq::restore_seed() const {
uint8_t seed_data[Seed::SIZE];

Serial.println("restore seed");
Serial.println(bytes_in_each_share);
Serial.println(nshares);

last_rv = sskr_combine(const_cast<const uint8_t **>(shares),
bytes_in_each_share,
nshares,
Expand All @@ -193,13 +187,13 @@ Seed * SSKRShareSeq::restore_seed() const {
class CborListen : public CborListener {
public:
void OnInteger(int32_t value){ };
void OnBytes(unsigned char *data, unsigned int size) {Serial.println("bytes"); memcpy(bytes, data, size); len = size;};
void OnBytes(unsigned char *data, unsigned int size) { memcpy(bytes, data, size); len = size; };
void OnString(String &str) {};
void OnArray(unsigned int size) {};
void OnMap(unsigned int size) {};
void OnTag(uint32_t tag) { tag_ = tag; };
void OnSpecial(uint32_t code) {Serial.println("tag");};
void OnError(const char *error) {Serial.println("error");};
void OnSpecial(uint32_t code) {};
void OnError(const char *error) {};

// we are gonna collect the tag and bytes
uint32_t tag_;
Expand Down
72 changes: 61 additions & 11 deletions seedtool/userinterface.ino
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,15 @@ void seedless_menu() {
}
}

void pendingCallback(const void*)
{
String txt = "One moment...";
Point p = text_center(txt.c_str());
g_display->fillScreen(GxEPD_WHITE);
g_display->setCursor(p.x, p.y);
g_display->println(txt);
}

void generate_seed() {
while (true) {
int xoff = 14;
Expand Down Expand Up @@ -591,7 +600,7 @@ void generate_seed() {
// This will take a few seconds; clear the screen
// immediately to let the user know something is
// happening ..
full_window_clear();
g_display->drawPaged(pendingCallback, 0);

if (g_bip39)
delete g_bip39;
Expand Down Expand Up @@ -1365,7 +1374,51 @@ struct BIP39WordlistState : WordListState {
}
};


// returns true if user wants bad checksum to get automatically fixed
// returns false if user wants to correct the mistake by himself
bool invalid_bip39_checksum(void) {

int xoff = 6;
int yoff = 6;

g_display->firstPage();
do
{
g_display->setPartialWindow(0, 0, 200, 200);
// g_display->fillScreen(GxEPD_WHITE);
g_display->setTextColor(GxEPD_BLACK);

int xx = xoff;
int yy = yoff + (H_FSB9 + YM_FSB9);
g_display->setFont(&FreeSansBold9pt7b);
g_display->setCursor(xx, yy);
display_printf("Bip39 bad checksum");
yy += H_FSB9 + YM_FSB9+20;

display_long_text(yy, "Press # to check your words again", 22);
display_long_text(yy+70, "Press A to fix the checksum", 19);
}
while (g_display->nextPage());

while (true) {
char key;
do {
key = g_keypad.getKey();
} while (key == NO_KEY);
switch (key) {
case '#':
return false;
case 'A':
return true;
default:
break;
}
}
}

void restore_bip39() {
bool fix_checksum = false;
BIP39WordlistState state(g_bip39, BIP39Seq::WORD_COUNT);
state.set_words((uint16_t *)NULL);

Expand Down Expand Up @@ -1493,6 +1546,7 @@ void restore_bip39() {
break;
case '#': // done
{
g_display->drawPaged(pendingCallback, 0);
uint16_t bip39_words[BIP39Seq::WORD_COUNT];
for (size_t ii = 0; ii < BIP39Seq::WORD_COUNT; ++ii)
bip39_words[ii] = state.wordndx[ii];
Expand All @@ -1508,17 +1562,13 @@ void restore_bip39() {
g_uistate = SEEDY_MENU;
return;
} else {
fix_checksum = invalid_bip39_checksum();
if (fix_checksum) {
bip39->fix_bip39_checksum();
for (size_t ii = 0; ii < BIP39Seq::WORD_COUNT; ++ii)
state.wordndx[ii] = bip39->get_word(ii);
}
delete bip39;
String lines[7];
size_t nlines = 0;
lines[nlines++] = "BIP39 Word List";
lines[nlines++] = "Checksum Error";
lines[nlines++] = "";
lines[nlines++] = "Check your word";
lines[nlines++] = "list carefully";
lines[nlines++] = "";
lines[nlines++] = "Press # to revisit";
interstitial_error(lines, nlines);
}
break;
}
Expand Down