From 99f58a00b7cf423f55767ba7268562b2914d66e7 Mon Sep 17 00:00:00 2001 From: Glenn Willen Date: Wed, 15 May 2019 14:02:39 -0700 Subject: [PATCH] Add functions to handle unique prefix mnemonics Common practice with bip39 mnemonics is to use unique four-character prefixes of wordlist words. In some cases (e.g. "steel" storage devices) there is not space to store more than four characters. So, enable users to enter unique prefixes instead of whole words. --- src/mnemonic.c | 17 ++++++++++++++--- src/mnemonic.h | 16 ++++++++++++++++ src/wordlist.c | 18 ++++++++++++++++++ src/wordlist.h | 13 +++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/mnemonic.c b/src/mnemonic.c index 06f5f908a..510277faa 100644 --- a/src/mnemonic.c +++ b/src/mnemonic.c @@ -59,8 +59,9 @@ char *mnemonic_from_bytes(const struct words *w, const unsigned char *bytes, siz return str; } -int mnemonic_to_bytes(const struct words *w, const char *mnemonic, - unsigned char *bytes_out, size_t len, size_t *written) +int mnemonic_to_bytes_internal(const struct words *w, const char *mnemonic, + size_t(*lookup_fn)(const struct words *, const char *), + unsigned char *bytes_out, size_t len, size_t *written) { struct words *mnemonic_w = wordlist_init(mnemonic); size_t i; @@ -80,7 +81,7 @@ int mnemonic_to_bytes(const struct words *w, const char *mnemonic, wally_clear(bytes_out, len); for (i = 0; i < mnemonic_w->len; ++i) { - size_t idx = wordlist_lookup_word(w, mnemonic_w->indices[i]); + size_t idx = lookup_fn(w, mnemonic_w->indices[i]); if (!idx) { wordlist_free(mnemonic_w); wally_clear(bytes_out, len); @@ -95,3 +96,13 @@ int mnemonic_to_bytes(const struct words *w, const char *mnemonic, wordlist_free(mnemonic_w); return WALLY_OK; } + +int mnemonic_to_bytes(const struct words *w, const char *mnemonic, + unsigned char *bytes_out, size_t len, size_t *written) { + return mnemonic_to_bytes_internal(w, mnemonic, wordlist_lookup_word, bytes_out, len, written); +} + +int mnemonic_prefix_to_bytes(const struct words *w, const char *mnemonic, + unsigned char *bytes_out, size_t len, size_t *written) { + return mnemonic_to_bytes_internal(w, mnemonic, wordlist_lookup_prefix, bytes_out, len, written); +} diff --git a/src/mnemonic.h b/src/mnemonic.h index a17797680..e6060b526 100644 --- a/src/mnemonic.h +++ b/src/mnemonic.h @@ -33,4 +33,20 @@ int mnemonic_to_bytes( size_t len, size_t *written); +/** + * Convert a mnemonic representation into a block of bytes. Accepts unique prefixes of wordlist words. + * + * @w: List of words. + * @mnemonic: Mnemonic sentence to store. + * @bytes_out: Where to store the converted representation. + * @len: The length of @bytes_out in bytes. + * @written: Destination for the number of bytes written. + */ +int mnemonic_prefix_to_bytes( + const struct words *w, + const char *mnemonic, + unsigned char *bytes_out, + size_t len, + size_t *written); + #endif /* LIBWALLY_MNEMONIC_H */ diff --git a/src/wordlist.c b/src/wordlist.c index fb1481931..98bac021d 100644 --- a/src/wordlist.c +++ b/src/wordlist.c @@ -83,6 +83,24 @@ size_t wordlist_lookup_word(const struct words *w, const char *word) return found ? found - w->indices + 1u : 0u; } +size_t wordlist_lookup_prefix(const struct words *w, const char *prefix) +{ + const size_t prefix_len = strlen(prefix); + size_t found = 0; + + size_t i; + for (i = 0; i < w->len; ++i) { + if (!strncmp(prefix, w->indices[i], prefix_len)) { + if (found) { + return 0; // prefix match is not unique + } + found = i + 1; + } + } + + return found; +} + const char *wordlist_lookup_index(const struct words *w, size_t idx) { if (idx >= w->len) diff --git a/src/wordlist.h b/src/wordlist.h index c8189672e..64f758d9b 100644 --- a/src/wordlist.h +++ b/src/wordlist.h @@ -45,6 +45,19 @@ size_t wordlist_lookup_word( const struct words *w, const char *word); +/** + * Find the unique word matching a given prefix in a wordlist. + * + * @w: Parsed list of words to look up in. + * @word: The prefix to look up. + * + * Returns 0 if not found OR not unique, idx + 1 otherwise. + * @see wordlist_init. + */ +size_t wordlist_lookup_prefix( + const struct words *w, + const char *prefix); + /** * Return the Nth word in a wordlist. *