Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/addresstype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
addressRet = tap;
return true;
}
case TxoutType::WITNESS_V2_P2MR: {
WitnessV2P2MR p2mr;
std::copy(vSolutions[0].begin(), vSolutions[0].end(), p2mr.begin());
addressRet = p2mr;
return true;
}
case TxoutType::WITNESS_UNKNOWN: {
addressRet = WitnessUnknown{vSolutions[0][0], vSolutions[1]};
return true;
Expand Down Expand Up @@ -187,6 +193,11 @@ class CScriptVisitor
return CScript() << OP_1 << ToByteVector(tap);
}

CScript operator()(const WitnessV2P2MR& p2mr) const
{
return CScript() << OP_2 << std::vector<unsigned char>(p2mr.begin(), p2mr.end());
}

CScript operator()(const WitnessUnknown& id) const
{
return CScript() << CScript::EncodeOP_N(id.GetWitnessVersion()) << id.GetWitnessProgram();
Expand Down Expand Up @@ -228,6 +239,7 @@ class ValidDestinationVisitor
bool operator()(const WitnessV0KeyHash& dest) const { return true; }
bool operator()(const WitnessV0ScriptHash& dest) const { return true; }
bool operator()(const WitnessV1Taproot& dest) const { return true; }
bool operator()(const WitnessV2P2MR& dest) const { return true; }
bool operator()(const WitnessUnknown& dest) const { return true; }
// Dilithium destination operators
bool operator()(const DilithiumPubKeyDestination& dest) const { return false; }
Expand Down
30 changes: 29 additions & 1 deletion src/addresstype.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,34 @@ struct WitnessV1Taproot : public XOnlyPubKey
explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {}
};

/** BIP360 P2MR: 32-byte script tree Merkle root (no public key) */
struct WitnessV2P2MR
{
static constexpr size_t SIZE = 32;
unsigned char m_merkle_root[SIZE];

WitnessV2P2MR() { memset(m_merkle_root, 0, SIZE); }
explicit WitnessV2P2MR(const std::vector<unsigned char>& data) {
assert(data.size() == SIZE);
memcpy(m_merkle_root, data.data(), SIZE);
}
explicit WitnessV2P2MR(const uint256& root) {
memcpy(m_merkle_root, root.begin(), SIZE);
}

const unsigned char* begin() const { return m_merkle_root; }
const unsigned char* end() const { return m_merkle_root + SIZE; }
unsigned char* begin() { return m_merkle_root; }
unsigned char* end() { return m_merkle_root + SIZE; }

friend bool operator==(const WitnessV2P2MR& a, const WitnessV2P2MR& b) {
return memcmp(a.m_merkle_root, b.m_merkle_root, SIZE) == 0;
}
friend bool operator<(const WitnessV2P2MR& a, const WitnessV2P2MR& b) {
return memcmp(a.m_merkle_root, b.m_merkle_root, SIZE) < 0;
}
};

// Dilithium destination types
struct DilithiumPubKeyDestination {
private:
Expand Down Expand Up @@ -175,7 +203,7 @@ struct WitnessUnknown
* * DilithiumWitnessV0ScriptHash: TxoutType::DILITHIUM_WITNESS_V0_SCRIPTHASH destination (P2DWSH address)
* A CTxDestination is the internal data type encoded in a btq address
*/
using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown, DilithiumPubKeyDestination, DilithiumPKHash, DilithiumScriptHash, DilithiumWitnessV0KeyHash, DilithiumWitnessV0ScriptHash>;
using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessV2P2MR, WitnessUnknown, DilithiumPubKeyDestination, DilithiumPKHash, DilithiumScriptHash, DilithiumWitnessV0KeyHash, DilithiumWitnessV0ScriptHash>;

/** Check whether a CTxDestination corresponds to one with an address. */
bool IsValidDestination(const CTxDestination& dest);
Expand Down
49 changes: 8 additions & 41 deletions src/crypto/dilithium_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include <cassert>
#include <cstring>
#include <cstdio>
#include <logging.h>

extern "C" {
#include "dilithium_wrapper.h"
Expand All @@ -23,75 +22,43 @@ extern "C" {

void CDilithiumKey::MakeNewKey()
{
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Starting\n");
MakeKeyData();
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - MakeKeyData completed\n");

// Generate random entropy for key generation
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Generating entropy\n");

std::array<unsigned char, DilithiumConstants::SECRET_KEY_SIZE> entropy;

// Bitcoin Core's GetStrongRandBytes is limited to 32 bytes, but Dilithium needs 2560 bytes
// We need to generate entropy in chunks and combine them
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Generating entropy in chunks (32 bytes each)\n");

// GetStrongRandBytes is limited to 32 bytes; Dilithium needs SECRET_KEY_SIZE bytes
constexpr size_t CHUNK_SIZE = 32;
constexpr size_t NUM_CHUNKS = DilithiumConstants::SECRET_KEY_SIZE / CHUNK_SIZE;

for (size_t i = 0; i < NUM_CHUNKS; i++) {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Generating chunk %zu/%zu\n", i + 1, NUM_CHUNKS);
try {
GetStrongRandBytes(Span<unsigned char>(entropy.data() + i * CHUNK_SIZE, CHUNK_SIZE));
} catch (const std::exception& e) {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - GetStrongRandBytes exception in chunk %zu: %s\n", i + 1, e.what());
ClearKeyData();
return;
} catch (...) {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - GetStrongRandBytes unknown exception in chunk %zu\n", i + 1);
ClearKeyData();
return;
}
}

// Handle any remaining bytes

size_t remaining_bytes = DilithiumConstants::SECRET_KEY_SIZE % CHUNK_SIZE;
if (remaining_bytes > 0) {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Generating remaining %zu bytes\n", remaining_bytes);
try {
GetStrongRandBytes(Span<unsigned char>(entropy.data() + NUM_CHUNKS * CHUNK_SIZE, remaining_bytes));
} catch (const std::exception& e) {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - GetStrongRandBytes exception for remaining bytes: %s\n", e.what());
ClearKeyData();
return;
} catch (...) {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - GetStrongRandBytes unknown exception for remaining bytes\n");
ClearKeyData();
return;
}
}

LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Entropy generated successfully\n");

// Generate public key buffer
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Creating public key buffer\n");

std::array<unsigned char, DilithiumConstants::PUBLIC_KEY_SIZE> pk;

// Generate keypair using Dilithium's btq_dilithium_keypair with proper entropy
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Calling btq_dilithium_keypair\n");

int result = btq_dilithium_keypair(pk.data(), entropy.data());
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - btq_dilithium_keypair returned: %d\n", result);


if (result != 0) {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Key generation failed, clearing key\n");
// Key generation failed, clear the key
ClearKeyData();
} else {
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Key generation successful, storing key material\n");
// Store the generated key material
memcpy(keydata->data(), entropy.data(), DilithiumConstants::SECRET_KEY_SIZE);
memcpy(keydata->data() + DilithiumConstants::SECRET_KEY_SIZE, pk.data(), DilithiumConstants::PUBLIC_KEY_SIZE);
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Key material stored successfully\n");
}
LogPrintf("DEBUG: CDilithiumKey::MakeNewKey - Completed\n");
}

bool CDilithiumKey::GenerateFromEntropy(const std::vector<unsigned char>& entropy)
Expand Down
14 changes: 14 additions & 0 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ class DestinationEncoder
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
}

std::string operator()(const WitnessV2P2MR& p2mr) const
{
std::vector<unsigned char> data = {2}; // SegWit version 2 -> bc1z prefix
data.reserve(53);
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, p2mr.begin(), p2mr.end());
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
}

std::string operator()(const WitnessUnknown& id) const
{
const std::vector<unsigned char>& program = id.GetWitnessProgram();
Expand Down Expand Up @@ -236,6 +244,12 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return tap;
}

if (version == 2 && data.size() == WITNESS_V2_P2MR_SIZE) {
WitnessV2P2MR p2mr;
std::copy(data.begin(), data.end(), p2mr.begin());
return p2mr;
}

if (version > 16) {
error_str = "Invalid Bech32 address witness version";
return CNoDestination();
Expand Down
1 change: 1 addition & 0 deletions src/outputtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest)
return OutputType::BECH32;
}
if (std::holds_alternative<WitnessV1Taproot>(dest) ||
std::holds_alternative<WitnessV2P2MR>(dest) ||
std::holds_alternative<WitnessUnknown>(dest)) {
return OutputType::BECH32M;
}
Expand Down
21 changes: 21 additions & 0 deletions src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,27 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
return false;
}
}

if (witnessversion == 2 && witnessprogram.size() == WITNESS_V2_P2MR_SIZE && !p2sh) {
// BIP360 P2MR spend (non-P2SH-wrapped, version 2, witness program size 32)
Span stack{tx.vin[i].scriptWitness.stack};
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
return false; // Annexes are nonstandard
}
if (stack.size() >= 2) {
const auto& control_block = SpanPopBack(stack);
SpanPopBack(stack);
if (control_block.empty()) return false;
if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
for (const auto& item : stack) {
if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) return false;
}
}
} else {
// P2MR has no key path; fewer than 2 elements is invalid
return false;
}
}
}
return true;
}
Expand Down
10 changes: 10 additions & 0 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,16 @@ class DescribeAddressVisitor
return obj;
}

UniValue operator()(const WitnessV2P2MR& p2mr) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", true);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", 2);
obj.pushKV("witness_program", HexStr(Span{p2mr.begin(), p2mr.end()}));
return obj;
}

UniValue operator()(const WitnessUnknown& id) const
{
UniValue obj(UniValue::VOBJ);
Expand Down
Loading
Loading