Make WitnessUnknown members private

Make sure that nothing else can change WitnessUnknown's data members by
making them private. Also change the program to use a vector rather than
C-style array.
This commit is contained in:
Andrew Chow 2023-09-05 12:03:46 -04:00
parent 238d29aff9
commit 8dd067088d
8 changed files with 32 additions and 42 deletions

View File

@ -87,11 +87,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
return true;
}
case TxoutType::WITNESS_UNKNOWN: {
WitnessUnknown unk;
unk.version = vSolutions[0][0];
std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
unk.length = vSolutions[1].size();
addressRet = unk;
addressRet = WitnessUnknown{vSolutions[0][0], vSolutions[1]};
return true;
}
case TxoutType::MULTISIG:
@ -138,7 +134,7 @@ public:
CScript operator()(const WitnessUnknown& id) const
{
return CScript() << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
return CScript() << CScript::EncodeOP_N(id.GetWitnessVersion()) << id.GetWitnessProgram();
}
};
} // namespace

View File

@ -69,22 +69,26 @@ struct WitnessV1Taproot : public XOnlyPubKey
//! CTxDestination subtype to encode any future Witness version
struct WitnessUnknown
{
unsigned int version;
unsigned int length;
unsigned char program[40];
private:
unsigned int m_version;
std::vector<unsigned char> m_program;
public:
WitnessUnknown(unsigned int version, const std::vector<unsigned char>& program) : m_version(version), m_program(program) {}
WitnessUnknown(int version, const std::vector<unsigned char>& program) : m_version(static_cast<unsigned int>(version)), m_program(program) {}
unsigned int GetWitnessVersion() const { return m_version; }
const std::vector<unsigned char>& GetWitnessProgram() const LIFETIMEBOUND { return m_program; }
friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
if (w1.version != w2.version) return false;
if (w1.length != w2.length) return false;
return std::equal(w1.program, w1.program + w1.length, w2.program);
if (w1.GetWitnessVersion() != w2.GetWitnessVersion()) return false;
return w1.GetWitnessProgram() == w2.GetWitnessProgram();
}
friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
if (w1.version < w2.version) return true;
if (w1.version > w2.version) return false;
if (w1.length < w2.length) return true;
if (w1.length > w2.length) return false;
return std::lexicographical_compare(w1.program, w1.program + w1.length, w2.program, w2.program + w2.length);
if (w1.GetWitnessVersion() < w2.GetWitnessVersion()) return true;
if (w1.GetWitnessVersion() > w2.GetWitnessVersion()) return false;
return w1.GetWitnessProgram() < w2.GetWitnessProgram();
}
};

View File

@ -66,12 +66,13 @@ public:
std::string operator()(const WitnessUnknown& id) const
{
if (id.version < 1 || id.version > 16 || id.length < 2 || id.length > 40) {
const std::vector<unsigned char>& program = id.GetWitnessProgram();
if (id.GetWitnessVersion() < 1 || id.GetWitnessVersion() > 16 || program.size() < 2 || program.size() > 40) {
return {};
}
std::vector<unsigned char> data = {(unsigned char)id.version};
data.reserve(1 + (id.length * 8 + 4) / 5);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.program, id.program + id.length);
std::vector<unsigned char> data = {(unsigned char)id.GetWitnessVersion()};
data.reserve(1 + (program.size() * 8 + 4) / 5);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, program.begin(), program.end());
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
}
@ -188,11 +189,7 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return CNoDestination();
}
WitnessUnknown unk;
unk.version = version;
std::copy(data.begin(), data.end(), unk.program);
unk.length = data.size();
return unk;
return WitnessUnknown{version, data};
} else {
error_str = strprintf("Invalid padding in Bech32 data section");
return CNoDestination();

View File

@ -303,8 +303,8 @@ public:
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", (int)id.version);
obj.pushKV("witness_program", HexStr({id.program, id.length}));
obj.pushKV("witness_version", id.GetWitnessVersion());
obj.pushKV("witness_program", HexStr(id.GetWitnessProgram()));
return obj;
}
};

View File

@ -186,7 +186,7 @@ FUZZ_TARGET(key, .init = initialize_key)
const CTxDestination tx_destination = GetDestinationForKey(pubkey, output_type);
assert(output_type == OutputType::LEGACY);
assert(IsValidDestination(tx_destination));
assert(CTxDestination{PKHash{pubkey}} == tx_destination);
assert(PKHash{pubkey} == *std::get_if<PKHash>(&tx_destination));
const CScript script_for_destination = GetScriptForDestination(tx_destination);
assert(script_for_destination.size() == 25);

View File

@ -188,15 +188,11 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no
tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}};
},
[&] {
WitnessUnknown witness_unknown{};
witness_unknown.version = fuzzed_data_provider.ConsumeIntegralInRange(2, 16);
std::vector<uint8_t> witness_unknown_program_1{fuzzed_data_provider.ConsumeBytes<uint8_t>(40)};
if (witness_unknown_program_1.size() < 2) {
witness_unknown_program_1 = {0, 0};
std::vector<unsigned char> program{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/40)};
if (program.size() < 2) {
program = {0, 0};
}
witness_unknown.length = witness_unknown_program_1.size();
std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
tx_destination = witness_unknown;
tx_destination = WitnessUnknown{fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(2, 16), program};
})};
Assert(call_size == std::variant_size_v<CTxDestination>);
return tx_destination;

View File

@ -249,10 +249,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
s.clear();
s << OP_1 << ToByteVector(pubkey);
BOOST_CHECK(ExtractDestination(s, address));
WitnessUnknown unk;
unk.length = 33;
unk.version = 1;
std::copy(pubkey.begin(), pubkey.end(), unk.program);
WitnessUnknown unk{1, ToByteVector(pubkey)};
BOOST_CHECK(std::get<WitnessUnknown>(address) == unk);
}

View File

@ -47,7 +47,7 @@ MessageVerificationResult MessageVerify(
return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED;
}
if (!(CTxDestination(PKHash(pubkey)) == destination)) {
if (!(PKHash(pubkey) == *std::get_if<PKHash>(&destination))) {
return MessageVerificationResult::ERR_NOT_SIGNED;
}