View in context in the libbitcoin Slack #general mirror.
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