/* * This file is part of the Flowee project * Copyright (C) 2021 Tom Zander * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "TestHDWallets.h" #include #include #include #include #include TestHDWallets::TestHDWallets() { ECC_Start(); // neded for crypto module, deriving pubkeys for instance. } TestHDWallets::~TestHDWallets() { ECC_Stop(); } void TestHDWallets::hdwallet() { QFETCH(QString, mnemonic); QFETCH(HDMasterKey::MnemonicType, mnemonicType); QFETCH(QString, masterPrivKey); QFETCH(QString, derivation); QFETCH(QString, bitcoinAddress); HDMasterKey mkey = HDMasterKey::fromMnemonic(mnemonic.toStdString(), mnemonicType); QVERIFY(mkey.isValid()); QCOMPARE(QString::fromStdString(mkey.privToString()), masterPrivKey); auto derivedKey = mkey.derive(derivation.toStdString()); QVERIFY(derivedKey.isValid()); auto id = derivedKey.getPubKey().getKeyId(); auto address = CashAddress::encodeCashAddr("bitcoincash", { CashAddress::PUBKEY_TYPE, std::vector(id.begin(), id.end())}); QCOMPARE(QString::fromStdString(address), bitcoinAddress); const auto derivationPathOrig = HDMasterKey::deriveFromString(derivation.toStdString()); auto iter = derivationPathOrig.begin(); for (size_t index = 0; index < derivationPathOrig.size(); ++index) { if ((derivationPathOrig[index] & HDMasterKey::Hardened) == 0) break; ++iter; } // Split into the hardened part and the rest. std::vector hardDerivPath(derivationPathOrig.begin(), iter); // See if the HDMasterPubkey also comes to the same conclusion using the xpub try { auto mPubKeyTestnet = HDMasterPubkey::fromXPub(mkey.toXPubString(hardDerivPath, HDMasterKey::Testnet)); QVERIFY(mPubKeyTestnet.isValid()); QCOMPARE(mPubKeyTestnet.chain(), HDMasterPubkey::Testnet); } catch (std::exception &e) { QFAIL(e.what()); } const auto xpub = mkey.toXPubString(hardDerivPath, HDMasterKey::MainChain); auto mPubKey = HDMasterPubkey::fromXPub(xpub); QVERIFY(mPubKey.isValid()); QCOMPARE(mPubKey.chain(), HDMasterPubkey::MainChain); QCOMPARE(mPubKey.toString(), xpub); auto derivedPubKey = mPubKey.derive(derivation.toStdString()); QVERIFY(derivedPubKey.isValid()); id = derivedPubKey.getKeyId(); address = CashAddress::encodeCashAddr("bitcoincash", { CashAddress::PUBKEY_TYPE, std::vector(id.begin(), id.end())}); QCOMPARE(QString::fromStdString(address), bitcoinAddress); // merthod 3, use the static method: HDMasterPubkey::fromHDMaster() auto mPubKey2 = HDMasterPubkey::fromHDMaster(mkey, derivation.toStdString()); QVERIFY(mPubKey2.isValid()); QCOMPARE(mPubKey2.chain(), HDMasterPubkey::MainChain); QCOMPARE(mPubKey2.toString(), xpub); derivedPubKey = mPubKey2.derive(derivation.toStdString()); QVERIFY(derivedPubKey.isValid()); id = derivedPubKey.getKeyId(); address = CashAddress::encodeCashAddr("bitcoincash", { CashAddress::PUBKEY_TYPE, std::vector(id.begin(), id.end())}); QCOMPARE(QString::fromStdString(address), bitcoinAddress); } void TestHDWallets::hdwallet_data() { QTest::addColumn("mnemonic"); // n-words of seed phrase. QTest::addColumn("mnemonicType"); QTest::addColumn("masterPrivKey"); QTest::addColumn("derivation"); QTest::addColumn("bitcoinAddress"); QTest::newRow("small-zero") << "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" << HDMasterKey::MnemonicType::BIP39Mnemonic << "xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu" << "m/0'/0'/0" << "bitcoincash:qp8aaqjvjrujq3fk2hdwcy98pur8hsd2c5rvshznat"; QTest::newRow("south") << "south monkey fire corn link estate burger lucky bronze pet chapter lamp" << HDMasterKey::MnemonicType::BIP39Mnemonic << "xprv9s21ZrQH143K4TATPFMZLvCbsFigZdnRDvD2E9dftwgLWUcEWDmRJFi7MuKRSCUd3cFgcyzpvEfAupd3AhK5JJ8RGxDtnYH8vXjYNn1kTmR" << "m/44'/145'/0'/0/0" << "bitcoincash:qrg0jddykyfeal70xduvyeathd3ulhm7hv22m3t7na"; QTest::newRow("south 2") << "south monkey fire corn link estate burger lucky bronze pet chapter lamp" << HDMasterKey::MnemonicType::BIP39Mnemonic << "xprv9s21ZrQH143K4TATPFMZLvCbsFigZdnRDvD2E9dftwgLWUcEWDmRJFi7MuKRSCUd3cFgcyzpvEfAupd3AhK5JJ8RGxDtnYH8vXjYNn1kTmR" << "m/44'/145'/0'/0/10" << "bitcoincash:qpk93uwjdpw6aezz0sy0vpv3my4sm0ths55ydxed2n"; QTest::newRow("Electrum Seed (coincidentally, matches BIP39 checksum) 1") << "already later tiger purse virtual author science beyond kind common victory excuse" << HDMasterKey::MnemonicType::ElectrumMnemonic << "xprv9s21ZrQH143K2s87gXNhmcutDi8P359wpyrZucphFTg4y98EXiwMPfHAeVi7pzAzSNViW83U4jJmLK46mTZuyKEUw3DKv2VidLwDKFA61ha" << "m/" << "bitcoincash:qzgcz9lwpwxw8x5svzl5k828ck0lwffjlckq5rt9n2"; QTest::newRow("Electrum Seed (coincidentally, matches BIP39 checksum) 2") << "already later tiger purse virtual author science beyond kind common victory excuse" << HDMasterKey::MnemonicType::ElectrumMnemonic << "xprv9s21ZrQH143K2s87gXNhmcutDi8P359wpyrZucphFTg4y98EXiwMPfHAeVi7pzAzSNViW83U4jJmLK46mTZuyKEUw3DKv2VidLwDKFA61ha" << "m/0/0" << "bitcoincash:qrrequmjr9v6qzr760qv7rxgtucmkyvgay8rv3m9rk"; QTest::newRow("Electrum Seed (coincidentally, matches BIP39 checksum) 3") << "already later tiger purse virtual author science beyond kind common victory excuse" << HDMasterKey::MnemonicType::BIP39Mnemonic << "xprv9s21ZrQH143K2PU84C6PDoEyoHd7Km7CqGNiAG72G2hoEW5Qt2MbCTbSk4boxdDpb5VAowN6PpW9srsGgopUxeG981ugr848vTWiufDLwu3" << "m/44'/145'/0'" << "bitcoincash:qzftdqk5g9npzu2hkvuq4c8p0egw479ctvs4lmnc8d"; QTest::newRow("Electrum Seed (coincidentally, matches BIP39 checksum) 4") << "already later tiger purse virtual author science beyond kind common victory excuse" << HDMasterKey::MnemonicType::BIP39Mnemonic << "xprv9s21ZrQH143K2PU84C6PDoEyoHd7Km7CqGNiAG72G2hoEW5Qt2MbCTbSk4boxdDpb5VAowN6PpW9srsGgopUxeG981ugr848vTWiufDLwu3" << "m/44'/145'/0'/0/0" << "bitcoincash:qr2vk59jsua8j5tefa7zh097re5xexu6csl2uju6v2"; QTest::newRow("Electrum Seed Long") << "panel swamp swear shoulder recycle one curious pistol seed abandon heart hunt emotion spare exhibit uncle safe galaxy gather pole smart involve common other" << HDMasterKey::MnemonicType::ElectrumMnemonic << "xprv9s21ZrQH143K2F39PdGLYXuR7ZiGZwFZkGuJwthhqfvuyoCzANxDHSV2Jf3G1B42Pv63L9gvVNb9JNwJHZLRmhaiD71MywquNoAJDivTxad" << "m/0/0" << "bitcoincash:qrdlftxwd0q7fptapa32x3jtv3g62xnytglwec2yxg"; }