From 9a8e982153d3acab75c0707e3c88872f6c5c781c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jan 2016 15:11:57 +0100 Subject: [PATCH] implement bip39 cache --- bip39.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- options.h | 6 ++++++ tests.c | 5 +++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/bip39.c b/bip39.c index 5985fe819..aa9ad9e1d 100644 --- a/bip39.c +++ b/bip39.c @@ -22,6 +22,7 @@ */ #include +#include #include "bip39.h" #include "hmac.h" @@ -29,6 +30,20 @@ #include "sha2.h" #include "pbkdf2.h" #include "bip39_english.h" +#include "options.h" + +#if USE_BIP39_CACHE + +static int bip39_cache_index = 0; + +static struct { + bool set; + char mnemonic[256]; + char passphrase[64]; + uint8_t seed[512 / 8]; +} bip39_cache[BIP39_CACHE_SIZE]; + +#endif const char *mnemonic_generate(int strength) { @@ -148,12 +163,36 @@ int mnemonic_check(const char *mnemonic) // passphrase must be at most 256 characters or code may crash void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)) { + int passphraselen = strlen(passphrase); +#if USE_BIP39_CACHE + int mnemoniclen = strlen(mnemonic); + // check cache + if (mnemoniclen < 256 && passphraselen < 64) { + int i; + for (i = 0; i < BIP39_CACHE_SIZE; i++) { + if (!bip39_cache[i].set) continue; + if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; + if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; + // found the correct entry + memcpy(seed, bip39_cache[i].seed, 512 / 8); + return; + } + } +#endif uint8_t salt[8 + 256 + 4]; - int saltlen = strlen(passphrase); memcpy(salt, "mnemonic", 8); - memcpy(salt + 8, passphrase, saltlen); - saltlen += 8; - pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); + memcpy(salt + 8, passphrase, passphraselen); + pbkdf2_hmac_sha512((const uint8_t *)mnemonic, strlen(mnemonic), salt, passphraselen + 8, BIP39_PBKDF2_ROUNDS, seed, 512 / 8, progress_callback); +#if USE_BIP39_CACHE + // store to cache + if (mnemoniclen < 256 && passphraselen < 64) { + bip39_cache[bip39_cache_index].set = true; + strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); + strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); + memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); + bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; + } +#endif } const char * const *mnemonic_wordlist(void) diff --git a/options.h b/options.h index 9612fdfcf..d5ac4ab33 100644 --- a/options.h +++ b/options.h @@ -50,4 +50,10 @@ #define BIP32_CACHE_MAXDEPTH 8 #endif +// implement BIP39 caching +#ifndef USE_BIP39_CACHE +#define USE_BIP39_CACHE 1 +#define BIP39_CACHE_SIZE 4 +#endif + #endif diff --git a/tests.c b/tests.c index 47d5724eb..8c34b48e5 100644 --- a/tests.c +++ b/tests.c @@ -880,6 +880,11 @@ START_TEST(test_mnemonic) ck_assert_str_eq(m, *b); mnemonic_to_seed(m, "TREZOR", seed, 0); ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); +#if USE_BIP39_CACHE + // try second time to check whether caching results work + mnemonic_to_seed(m, "TREZOR", seed, 0); + ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); +#endif a += 3; b += 3; c += 3; } }