Merge pull request #5662 from nuttycom/legacy_seed_to_mnemonic

Derive the mnemonic seed from the legacy HD seed, if one is available.
This commit is contained in:
sasha 2022-03-14 20:32:09 -07:00 committed by GitHub
commit 3a957618b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 18 deletions

View File

@ -3123,7 +3123,10 @@ void CWallet::GenerateNewSeed(Language language)
{
LOCK(cs_wallet);
auto seed = MnemonicSeed::Random(BIP44CoinType(), language, WALLET_MNEMONIC_ENTROPY_LENGTH);
auto legacySeed = GetLegacyHDSeed();
auto seed = legacySeed.has_value() ?
MnemonicSeed::FromLegacySeed(legacySeed.value(), BIP44CoinType(), language) :
MnemonicSeed::Random(BIP44CoinType(), language, WALLET_MNEMONIC_ENTROPY_LENGTH);
int64_t nCreationTime = GetTime();

View File

@ -9,31 +9,60 @@
using namespace libzcash;
std::optional<MnemonicSeed> MnemonicSeed::FromEntropy(const RawHDSeed& entropy, uint32_t bip44CoinType, Language language) {
const char* phrase = zip339_entropy_to_phrase(language, entropy.data(), entropy.size());
SecureString mnemonic(phrase);
zip339_free_phrase(phrase);
// The phrase returned from zip339_entropy_to_phrase should always be a
// valid UTF-8 string; this `.value()` unwrap will correctly throw a
// `std::bad_optional_access` exception if that invariant does not hold.
auto seed = MnemonicSeed::ForPhrase(language, mnemonic).value();
// Verify that the seed data is valid entropy for unified spending keys at
// account 0 and at both the public & private chain levels for account 0x7FFFFFFF.
// It is not necessary to check for a valid diversified Sapling address at
// account 0x7FFFFFFF because derivation via the legacy path can simply search
// for a valid diversifier; unlike in the unified spending key case, diversifier
// indices don't need to line up with anything.
if (ZcashdUnifiedSpendingKey::ForAccount(seed, bip44CoinType, 0).has_value() &&
transparent::AccountKey::ForAccount(seed, bip44CoinType, ZCASH_LEGACY_ACCOUNT).has_value()) {
return seed;
} else {
return std::nullopt;
}
}
MnemonicSeed MnemonicSeed::Random(uint32_t bip44CoinType, Language language, size_t entropyLen)
{
assert(entropyLen >= 32);
while (true) { // loop until we find usable entropy
RawHDSeed entropy(entropyLen, 0);
GetRandBytes(entropy.data(), entropyLen);
const char* phrase = zip339_entropy_to_phrase(language, entropy.data(), entropyLen);
SecureString mnemonic(phrase);
zip339_free_phrase(phrase);
// The phrase returned from zip339_entropy_to_phrase should always be a
// valid UTF-8 string; this `.value()` unwrap will correctly throw a
// `std::bad_optional_access` exception if that invariant does not hold.
auto seed = MnemonicSeed::ForPhrase(language, mnemonic).value();
// Verify that the seed data is valid entropy for unified spending keys at
// account 0 and at both the public & private chain levels for account 0x7FFFFFFF.
// It is not necessary to check for a valid diversified Sapling address at
// account 0x7FFFFFFF because derivation via the legacy path can simply search
// for a valid diversifier; unlike in the unified spending key case, diversifier
// indices don't need to line up with anything.
if (ZcashdUnifiedSpendingKey::ForAccount(seed, bip44CoinType, 0).has_value() &&
transparent::AccountKey::ForAccount(seed, bip44CoinType, ZCASH_LEGACY_ACCOUNT).has_value()) {
return seed;
auto seed = MnemonicSeed::FromEntropy(entropy, bip44CoinType, language);
if (seed.has_value()) {
return seed.value();
}
}
}
MnemonicSeed MnemonicSeed::FromLegacySeed(const HDSeed& legacySeed, uint32_t bip44CoinType, Language language)
{
auto rawSeed = legacySeed.RawSeed();
if (rawSeed.size() != 32) {
throw std::runtime_error("Mnemonic seed derivation is only supported for 32-byte legacy seeds.");
}
for (int nonce = 0; nonce < 256; nonce++) {
auto seed = MnemonicSeed::FromEntropy(rawSeed, bip44CoinType, language);
if (seed.has_value()) {
return seed.value();
} else {
rawSeed[0]++;
}
}
throw std::runtime_error("Failed to find a valid mnemonic seed that could be derived from the legacy seed.");
}

View File

@ -37,6 +37,10 @@ public:
*/
static MnemonicSeed Random(uint32_t bip44CoinType, Language language = English, size_t entropyLen = 32);
static MnemonicSeed FromLegacySeed(const HDSeed& legacySeed, uint32_t bip44CoinType, Language language = English);
static std::optional<MnemonicSeed> FromEntropy(const RawHDSeed& entropy, uint32_t bip44CoinType, Language language = English);
static std::string LanguageName(Language language) {
switch (language) {
case English: