diff --git a/.gitignore b/.gitignore
index 6e7db3614..4642caf33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,10 @@ console/bx
/release/bx
/release/bx.exe
*.zpl
+
+build-libbitcoin-explorer
+libbitcoin_explorer_test_runner.sh.log
+libbitcoin_explorer_test_runner.sh.trs
+test-suite.log
+test.log
+test/libbitcoin_explorer_test
diff --git a/include/bitcoin/explorer/commands/electrum-new.hpp b/include/bitcoin/explorer/commands/electrum-new.hpp
index d7b7da227..7268f915f 100644
--- a/include/bitcoin/explorer/commands/electrum-new.hpp
+++ b/include/bitcoin/explorer/commands/electrum-new.hpp
@@ -58,8 +58,10 @@ namespace commands {
/**
* Various localizable strings.
*/
-#define BX_EC_ELECTRUM_NEW_UNSUPPORTED \
- "The electrum-new command requires an ICU build."
+#define BX_ELECTRUM_NEW_INVALID_SEED \
+ "The seed size is not supported."
+#define BX_ELECTRUM_REQUIRES_ICU \
+ "The command requires an ICU build."
/**
* Class to implement the electrum-new command.
diff --git a/include/bitcoin/explorer/commands/electrum-to-seed.hpp b/include/bitcoin/explorer/commands/electrum-to-seed.hpp
index 9836cc10e..85ffd08f3 100644
--- a/include/bitcoin/explorer/commands/electrum-to-seed.hpp
+++ b/include/bitcoin/explorer/commands/electrum-to-seed.hpp
@@ -58,7 +58,7 @@ namespace commands {
/**
* Various localizable strings.
*/
-#define BX_EC_ELECTRUM_TO_SEED_PASSPHRASE_UNSUPPORTED \
+#define BX_ELECTRUM_TO_SEED_REQUIRES_ICU \
"The passphrase option requires an ICU build."
/**
diff --git a/include/bitcoin/explorer/commands/mnemonic-decode.hpp b/include/bitcoin/explorer/commands/mnemonic-decode.hpp
index 3ff5e2220..8e373001b 100644
--- a/include/bitcoin/explorer/commands/mnemonic-decode.hpp
+++ b/include/bitcoin/explorer/commands/mnemonic-decode.hpp
@@ -59,7 +59,7 @@ namespace commands {
* Various localizable strings.
*/
#define BX_MNEMONIC_DECODE_OBSOLETE \
- "Electrum style key functions are obsolete. Use mnemonic-to-seed (BIP39) command instead."
+ "Electrum version 1 functions are obsolete. Use electrum-to-seed or mnemonic-to-seed (BIP39) command instead."
/**
* Class to implement the mnemonic-decode command.
diff --git a/include/bitcoin/explorer/commands/mnemonic-encode.hpp b/include/bitcoin/explorer/commands/mnemonic-encode.hpp
index c061cfd0d..806d975eb 100644
--- a/include/bitcoin/explorer/commands/mnemonic-encode.hpp
+++ b/include/bitcoin/explorer/commands/mnemonic-encode.hpp
@@ -59,7 +59,7 @@ namespace commands {
* Various localizable strings.
*/
#define BX_MNEMONIC_ENCODE_OBSOLETE \
- "Electrum style key functions are obsolete. Use mnemonic-new (BIP39) command instead."
+ "Electrum version 1 functions are obsolete. Use electrum-new or mnemonic-new (BIP39) command instead."
/**
* Class to implement the mnemonic-encode command.
diff --git a/include/bitcoin/explorer/commands/mnemonic-new.hpp b/include/bitcoin/explorer/commands/mnemonic-new.hpp
index 88e517ff8..d4646e8b1 100644
--- a/include/bitcoin/explorer/commands/mnemonic-new.hpp
+++ b/include/bitcoin/explorer/commands/mnemonic-new.hpp
@@ -58,7 +58,7 @@ namespace commands {
/**
* Various localizable strings.
*/
-#define BX_EC_MNEMONIC_NEW_INVALID_ENTROPY \
+#define BX_EC_MNEMONIC_NEW_INVALID_SEED \
"The seed length in bytes is not evenly divisible by 32 bits."
/**
diff --git a/include/bitcoin/explorer/commands/mnemonic-to-seed.hpp b/include/bitcoin/explorer/commands/mnemonic-to-seed.hpp
index 5eb1abdc4..341518405 100644
--- a/include/bitcoin/explorer/commands/mnemonic-to-seed.hpp
+++ b/include/bitcoin/explorer/commands/mnemonic-to-seed.hpp
@@ -60,7 +60,7 @@ namespace commands {
*/
#define BX_EC_MNEMONIC_TO_SEED_LENGTH_INVALID_SENTENCE \
"The number of words must be divisible by 3."
-#define BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED \
+#define BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU \
"The passphrase option requires an ICU build."
#define BX_EC_MNEMONIC_TO_SEED_INVALID_IN_LANGUAGE \
"The specified words are not a valid mnemonic in the specified dictionary."
diff --git a/install.sh b/install.sh
index b4b443a60..d1a4d4f6b 100755
--- a/install.sh
+++ b/install.sh
@@ -279,8 +279,8 @@ fi
# Set the prefix-based package config directory.
PREFIX_PKG_CONFIG_DIR="$PREFIX/lib/pkgconfig"
-# Augment PKG_CONFIG_PATH search path with our prefix.
-export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PREFIX_PKG_CONFIG_DIR"
+# Prioritize prefix package config in PKG_CONFIG_PATH search path.
+export PKG_CONFIG_PATH="$PREFIX_PKG_CONFIG_DIR:$PKG_CONFIG_PATH"
# Set a package config save path that can be passed via our builds.
with_pkgconfigdir="--with-pkgconfigdir=$PREFIX_PKG_CONFIG_DIR"
diff --git a/model/generate.xml b/model/generate.xml
index d4685a63b..7ef8f4d28 100644
--- a/model/generate.xml
+++ b/model/generate.xml
@@ -208,14 +208,15 @@
-
+
+
-
+
@@ -412,17 +413,17 @@
-
+
-
+
-
+
@@ -430,7 +431,7 @@
-
+
diff --git a/src/commands/electrum-new.cpp b/src/commands/electrum-new.cpp
index 341404505..1f640f92a 100644
--- a/src/commands/electrum-new.cpp
+++ b/src/commands/electrum-new.cpp
@@ -18,9 +18,8 @@
*/
#include
-#include
+#include
#include
-#include
#include
namespace libbitcoin {
@@ -28,8 +27,10 @@ namespace explorer {
namespace commands {
using namespace bc::wallet;
-console_result electrum_new::invoke(std::ostream& output,
- std::ostream& error)
+// Requires a seed of at least 17 bytes (136 bits).
+static const size_t minimum_electrum_words = 12;
+
+console_result electrum_new::invoke(std::ostream& output, std::ostream& error)
{
#ifdef WITH_ICU
// Bound parameters.
@@ -37,14 +38,30 @@ console_result electrum_new::invoke(std::ostream& output,
const data_chunk& seed = get_seed_argument();
const auto prefix = get_prefix_option();
+ // trunc(log2(2048)) = 11
+ const auto word_bits = static_cast(std::log2(dictionary_size));
+
+ // 17 * 8 = 136
+ const auto seed_bits = seed.size() * byte_bits;
+
+ // 136 / 11 = 12
+ const auto words = seed_bits / word_bits;
+
+ if (words < minimum_electrum_words)
+ {
+ error << BX_ELECTRUM_NEW_INVALID_SEED << std::endl;
+ return console_result::failure;
+ }
+
// If 'any' default to first ('en'), otherwise the one specified.
const auto dictionary = language.front();
- const auto words = electrum::create_mnemonic(seed, *dictionary, prefix);
- output << join(words) << std::endl;
+ auto mnemonic = electrum::create_mnemonic(seed, *dictionary, prefix);
+
+ output << join(mnemonic) << std::endl;
return console_result::okay;
#else
- error << BX_EC_ELECTRUM_NEW_UNSUPPORTED << std::endl;
+ error << BX_ELECTRUM_REQUIRES_ICU << std::endl;
return console_result::failure;
#endif
}
diff --git a/src/commands/electrum-to-seed.cpp b/src/commands/electrum-to-seed.cpp
index eee82cc05..f068cc1f5 100644
--- a/src/commands/electrum-to-seed.cpp
+++ b/src/commands/electrum-to-seed.cpp
@@ -42,7 +42,7 @@ console_result electrum_to_seed::invoke(std::ostream& output,
// The passphrase requires ICU normalization.
if (!passphrase.empty())
{
- error << BX_EC_ELECTRUM_TO_SEED_PASSPHRASE_UNSUPPORTED << std::endl;
+ error << BX_ELECTRUM_TO_SEED_REQUIRES_ICU << std::endl;
return console_result::failure;
}
diff --git a/src/commands/mnemonic-new.cpp b/src/commands/mnemonic-new.cpp
index 723e03d74..e39346fac 100644
--- a/src/commands/mnemonic-new.cpp
+++ b/src/commands/mnemonic-new.cpp
@@ -38,7 +38,7 @@ console_result mnemonic_new::invoke(std::ostream& output,
if ((entropy_size % bc::wallet::mnemonic_seed_multiple) != 0)
{
- error << BX_EC_MNEMONIC_NEW_INVALID_ENTROPY << std::endl;
+ error << BX_EC_MNEMONIC_NEW_INVALID_SEED << std::endl;
return console_result::failure;
}
diff --git a/src/commands/mnemonic-to-seed.cpp b/src/commands/mnemonic-to-seed.cpp
index 88fb02236..d7b40208e 100644
--- a/src/commands/mnemonic-to-seed.cpp
+++ b/src/commands/mnemonic-to-seed.cpp
@@ -62,7 +62,7 @@ console_result mnemonic_to_seed::invoke(std::ostream& output,
#else
if (!passphrase.empty())
{
- error << BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED << std::endl;
+ error << BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU << std::endl;
return console_result::failure;
}
diff --git a/src/commands/seed.cpp b/src/commands/seed.cpp
index bd6ec9dea..8a4ca99af 100644
--- a/src/commands/seed.cpp
+++ b/src/commands/seed.cpp
@@ -18,7 +18,6 @@
*/
#include
-#include
#include
#include
#include
diff --git a/test/commands/electrum-new.cpp b/test/commands/electrum-new.cpp
index 876fd28ed..c2f355c52 100644
--- a/test/commands/electrum-new.cpp
+++ b/test/commands/electrum-new.cpp
@@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(electrum_new__invoke__17_bytes__okay_output)
BX_REQUIRE_OUTPUT("giggle crush argue inflict wear defy combine evolve tiger spatial crumble fury\n");
}
-BOOST_AUTO_TEST_CASE(electrum_new__invoke__dictionary_prefix__okay_output)
+BOOST_AUTO_TEST_CASE(electrum_new__invoke__en_dictionary_prefix__okay_output)
{
BX_DECLARE_COMMAND(electrum_new);
command.set_seed_argument({ "05e669b4270f4e25bce6fc3736170d423c" });
@@ -44,6 +44,16 @@ BOOST_AUTO_TEST_CASE(electrum_new__invoke__dictionary_prefix__okay_output)
BX_REQUIRE_OUTPUT("giggle crush argue inflict wear defy combine evolve tiger spatial crumble fury\n");
}
+BOOST_AUTO_TEST_CASE(electrum_new__invoke__es_dictionary_prefix__okay_output)
+{
+ BX_DECLARE_COMMAND(electrum_new);
+ command.set_seed_argument({ "05e669b4270f4e25bce6fc3736170d423c" });
+ command.set_language_option({ "es" });
+ command.set_prefix_option({ "standard" });
+ BX_REQUIRE_OKAY(command.invoke(output, error));
+ BX_REQUIRE_OUTPUT("gigante codo ámbar insecto verbo cráter celoso entrar tarjeta sala coco frito\n");
+}
+
BOOST_AUTO_TEST_CASE(electrum_new__invoke__32_bytes__okay_output)
{
BX_DECLARE_COMMAND(electrum_new);
diff --git a/test/commands/mnemonic-new.cpp b/test/commands/mnemonic-new.cpp
index 711056c6d..3d54933df 100644
--- a/test/commands/mnemonic-new.cpp
+++ b/test/commands/mnemonic-new.cpp
@@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_new__invoke__136_bits__failure_error)
BX_DECLARE_COMMAND(mnemonic_new);
command.set_seed_argument({ "baadf00dbaadf00dbaadf00dbaadf00dff" });
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_NEW_INVALID_ENTROPY "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_NEW_INVALID_SEED "\n");
}
BOOST_AUTO_TEST_CASE(mnemonic_new__invoke__128_bits__okay_output)
diff --git a/test/commands/mnemonic-to-seed.cpp b/test/commands/mnemonic-to-seed.cpp
index 0f6870bb4..5b14d2fcb 100644
--- a/test/commands/mnemonic-to-seed.cpp
+++ b/test/commands/mnemonic-to-seed.cpp
@@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__standard__okay_output)
BX_REQUIRE_OUTPUT("2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase__okay_output
BX_REQUIRE_OUTPUT("3e52585ea1275472a82fa0dcd84121e742140f64a302eca7c390832ba428c707a7ebf449267ae592c51f1740259226e31520de39fd8f33e08788fd21221c6f4e\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase_and_words__o
BX_REQUIRE_OUTPUT("e72505021b97e15171fe09e996898888579c4196c445d7629762c5b09586e3fb3d68380120b8d8a6ed6f9a73306dab7bf54127f3a610ede2a2d5b4e59916ac73\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase_and_words_an
BX_REQUIRE_OUTPUT("e72505021b97e15171fe09e996898888579c4196c445d7629762c5b09586e3fb3d68380120b8d8a6ed6f9a73306dab7bf54127f3a610ede2a2d5b4e59916ac73\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase_and_words_es
BX_REQUIRE_OUTPUT("e72505021b97e15171fe09e996898888579c4196c445d7629762c5b09586e3fb3d68380120b8d8a6ed6f9a73306dab7bf54127f3a610ede2a2d5b4e59916ac73\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase_and_words_an
BX_REQUIRE_OUTPUT("a92538e2827914d13ead2b426aa45ebd0b16590318e04b6ef78780c8eb803269f08662dd74bc4982e7cbb71f15c71f310168457d570ad5fd89c98a6095bac560\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase_and_words_fr
BX_REQUIRE_OUTPUT("a92538e2827914d13ead2b426aa45ebd0b16590318e04b6ef78780c8eb803269f08662dd74bc4982e7cbb71f15c71f310168457d570ad5fd89c98a6095bac560\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase_and_words_an
BX_REQUIRE_OUTPUT("b145e13882dc52b64a868ba35c3a95de5f468f2963d9feca9a8b345e3a60ef02af42347f99bc35a72d88bdabe8d63a4f5b61a63d6cd549461b5dd11027b66cf7\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}
@@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(mnemonic_to_seed__invoke__non_ascii_passphrase_and_words_it
BX_REQUIRE_OUTPUT("b145e13882dc52b64a868ba35c3a95de5f468f2963d9feca9a8b345e3a60ef02af42347f99bc35a72d88bdabe8d63a4f5b61a63d6cd549461b5dd11027b66cf7\n");
#else
BX_REQUIRE_FAILURE(command.invoke(output, error));
- BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_PASSPHRASE_UNSUPPORTED "\n");
+ BX_REQUIRE_ERROR(BX_EC_MNEMONIC_TO_SEED_REQUIRES_ICU "\n");
#endif
}