Files

201 lines
7.3 KiB
C++
Raw Permalink Normal View History

2022-12-11 20:05:46 +01:00
/*
* This file is part of the Flowee project
* Copyright (C) 2011-2015 The Bitcoin Core developers
* Copyright (C) 2022 Tom Zander <tom@flowee.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "base58_tests.h"
#include <encodings_legacy.h>
2023-11-24 18:16:32 +01:00
#include <primitives/PrivateKey.h>
2022-12-11 20:05:46 +01:00
#include <primitives/script.h>
#include <uint256.h>
#include <util.h>
2026-05-14 13:13:40 +02:00
#include <chainparams.h>
2022-12-11 20:05:46 +01:00
#include <utilstrencodings.h>
// Visitor to check address type
class TestAddrTypeVisitor : public boost::static_visitor<bool>
{
private:
std::string exp_addrType;
public:
TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { }
bool operator()(const KeyId &id) const
{
return (exp_addrType == "pubkey");
}
bool operator()(const CScriptID &id) const
{
return (exp_addrType == "script");
}
bool operator()(const CNoDestination &no) const
{
return (exp_addrType == "none");
}
};
void Base58Tests::base58KeysValidParse()
{
QFile in(":/base58_keys_valid.json");
QVERIFY(in.open(QIODevice::ReadOnly));
auto testDoc = QJsonDocument::fromJson(in.readAll());
QVERIFY(testDoc.isArray());
auto tests = testDoc.array();
CBitcoinSecret secret;
CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN);
for (auto row = tests.begin(); row != tests.end(); ++row) {
auto test = row->toArray();
if (test.size() < 3) { // Allow for extra stuff (useful for comments)
QFAIL("Bad test");
continue;
}
std::string exp_base58string = test[0].toString().toStdString();
auto exp_payload = ParseHex(test[1].toString().toStdString());
auto metadata = test[2].toObject();
bool isPrivkey = metadata.value("isPrivkey").toBool();
bool isTestnet = metadata.value("isTestnet").toBool();
if (isTestnet)
SelectParams(CBaseChainParams::TESTNET);
else
SelectParams(CBaseChainParams::MAIN);
if (isPrivkey) {
PrivateKey key;
bool isCompressed = metadata.value("isCompressed").toBool();
// Must be valid private key
// Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
QVERIFY2(secret.SetString(exp_base58string), "!SetString");
QVERIFY2(secret.IsValid(), "!IsValid");
PrivateKey privkey = secret.GetKey();
QVERIFY2(privkey.isCompressed() == isCompressed, "compressed mismatch");
QVERIFY2(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch");
// Private key must be invalid public key
addr.SetString(exp_base58string);
QVERIFY2(!addr.IsValid(), "IsValid privkey as pubkey");
}
else {
std::string exp_addrType = metadata.value("addrType").toString().toStdString(); // "script" or "pubkey"
// Must be valid public key
QVERIFY2(addr.SetString(exp_base58string), "SetString");
QVERIFY2(addr.IsValid(), "!IsValid");
QVERIFY2(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch");
CTxDestination dest = addr.Get();
QVERIFY2(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch");
// Public key must be invalid private key
secret.SetString(exp_base58string);
QVERIFY2(!secret.IsValid(), "IsValid pubkey as privkey");
}
}
}
// Goal: check that generated keys match test vectors
void Base58Tests::base58KeysValidGen()
{
QFile in(":/base58_keys_valid.json");
QVERIFY(in.open(QIODevice::ReadOnly));
auto testDoc = QJsonDocument::fromJson(in.readAll());
QVERIFY(testDoc.isArray());
auto tests = testDoc.array();
for (unsigned int idx = 0; idx < tests.size(); idx++) {
auto test = tests[idx].toArray();
if (test.size() < 3) { // Allow for extra stuff (useful for comments)
QFAIL("Bad test");
continue;
}
std::string exp_base58string = test[0].toString().toStdString();
auto exp_payload = ParseHex(test[1].toString().toStdString());
auto metadata = test[2].toObject();
bool isPrivkey = metadata.value("isPrivkey").toBool();
bool isTestnet = metadata.value("isTestnet").toBool();
if (isTestnet)
SelectParams(CBaseChainParams::TESTNET);
else
SelectParams(CBaseChainParams::MAIN);
if (isPrivkey) {
bool isCompressed = metadata.value("isCompressed").toBool();
PrivateKey key;
key.set(exp_payload.begin(), exp_payload.end(), isCompressed);
QVERIFY(key.isValid());
CBitcoinSecret secret;
secret.SetKey(key);
QVERIFY2(secret.ToString() == exp_base58string, "result mismatch");
}
else {
std::string exp_addrType = metadata.value("addrType").toString().toStdString(); // "script" or "pubkey"
CTxDestination dest;
if(exp_addrType == "pubkey") {
dest = KeyId(uint160(exp_payload));
}
else if(exp_addrType == "script") {
dest = CScriptID(uint160(exp_payload));
}
else if(exp_addrType == "none") {
dest = CNoDestination();
}
else {
QFAIL("Bad addrtype");
continue;
}
CBitcoinAddress addrOut;
QVERIFY2(addrOut.Set(dest), "encode dest");
QVERIFY2(addrOut.ToString() == exp_base58string, "mismatch");
}
}
// Visiting a CNoDestination must fail
CBitcoinAddress dummyAddr;
CTxDestination nodest = CNoDestination();
QVERIFY(!dummyAddr.Set(nodest));
SelectParams(CBaseChainParams::MAIN);
}
// Goal: check that base58 parsing code is robust against a variety of corrupted data
void Base58Tests::base58KeysInvalid()
{
QFile in(":/base58_keys_invalid.json");
QVERIFY(in.open(QIODevice::ReadOnly));
auto testDoc = QJsonDocument::fromJson(in.readAll());
QVERIFY(testDoc.isArray());
auto tests = testDoc.array();
CBitcoinSecret secret;
CBitcoinAddress addr;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
auto test = tests[idx].toArray();
if (test.size() < 1) { // Allow for extra stuff (useful for comments)
QFAIL("Bad test");
continue;
}
std::string exp_base58string = test[0].toString().toStdString();
// must be invalid as public and as private key
addr.SetString(exp_base58string);
QVERIFY2(!addr.IsValid(), "IsValid pubkey");
secret.SetString(exp_base58string);
QVERIFY2(!secret.IsValid(), "IsValid privkey");
}
}