Bitcoin full node and query server

May 18, 2025

View in context in the libbitcoin Slack #general mirror.

evoskuil02:28
That one function is all this:
namespace taproot {

static hash_digest leaf_hash(uint8_t version,
    const script& script) NOEXCEPT
{
    hash_digest out{};
    stream::out::fast stream{ out };
    hash::sha256t::fast<"TapLeaf"> sink{ stream };
    sink.write_byte(version);
    script.to_data(sink, true);
    sink.flush();
    return out;
}

static hash_digest tweak_hash(const ec_xonly& key,
    const hash_digest& merkle) NOEXCEPT
{
    hash_digest out{};
    stream::out::fast stream{ out };
    hash::sha256t::fast<"TapTweak"> sink{ stream };
    sink.write_bytes(key);
    sink.write_bytes(merkle);
    sink.flush();
    return out;
}

static hash_digest branch_hash(const hash_digest& left,
    const hash_digest& right) NOEXCEPT
{
    hash_digest out{};
    stream::out::fast stream{ out };
    hash::sha256t::fast<"TapBranch"> sink{ stream };

    if (std::lexicographical_compare(left.begin(), left.end(),
        right.begin(), right.end()))
    {
        sink.write_bytes(left);
        sink.write_bytes(right);
    }
    else
    {
        sink.write_bytes(right);
        sink.write_bytes(left);
    }

    sink.flush();
    return out;
}

static hash_digest merkle_root(const data_chunk& control,
    const hash_digest& tapleaf_hash) NOEXCEPT
{
    BC_ASSERT(is_valid_control_block(control));

    constexpr auto start = add1(ec_xonly_size);
    const auto bytes = floored_subtract(control.size(), start);
    const auto count = floored_divide(bytes, ec_xonly_size);
    const auto begin = std::next(control.data(), start);
    const auto nodes = unsafe_array_cast<ec_xonly, taproot_max_keys>(begin);

    hash_digest hash{ tapleaf_hash };
    for (size_t node{}; node < count; ++node)
        hash = branch_hash(hash, nodes.at(node));

    return hash;
}

static bool verify_commitment(const data_chunk& control,
    const data_chunk& program, const hash_digest& hash,
    bool parity) NOEXCEPT
{
    BC_ASSERT(is_valid_control_block(control));

    const auto out = program.data();
    const auto& out_key = unsafe_array_cast<uint8_t, ec_xonly_size>(out);
    const auto in = std::next(control.data());
    const auto& in_key = unsafe_array_cast<uint8_t, ec_xonly_size>(in);
    const auto root = merkle_root(control, hash);
    const auto tweak = tweak_hash(out_key, root);
    return schnorr::verify_commitment(in_key, tweak, out_key, parity);
}

struct tap
{
    operator bool() const NOEXCEPT { return version == tapscript_version; }
    uint8_t version;
    bool parity;
};

static tap parse(const data_chunk& control) NOEXCEPT
{
    BC_ASSERT(!control.empty());

    const auto byte = control.front();
    return
    {
        bit_and(byte, tapscript_mask),
        to_bool(bit_and(byte, bit_not(tapscript_mask)))
    };
}

} // namespace taproot