Source code for btclib_secp256k1.hashes

# Copyright (c) The btclib developers
# Distributed under the MIT software license, see the accompanying
# LICENSE file or https://opensource.org/license/mit for the full text.

"""Tagged hashing, according to BIP340.

https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
"""

from __future__ import annotations

from . import BytesLike, ffi, lib
from ._scalar import octets
from .context import ctx

__all__ = ["tagged_sha256"]

# the buffer the hash is written into: SHA256 has one output length and
# this is it. The width is stated once and the type is built from it, and
# what that saves is `ffi.sizeof` of a cdata per call, a hundredth of a
# microsecond of the 0.596 a tagged hash of an empty message costs --
# 0.016 in the session `xonly.py` names, and not a figure this site can be
# held to between sessions: that comment says why
_HASH_SIZE = 32
_HASH_BUFFER_TYPE = ffi.typeof(f"char[{_HASH_SIZE}]")


[docs] def tagged_sha256(tag_bytes: BytesLike, msg_bytes: BytesLike) -> bytes: """Return the BIP340 tagged hash of a message. That is SHA256(SHA256(tag) || SHA256(tag) || msg): the tag separates the domains of the protocols using it, so that what one of them signs cannot be read as a message of another. The BIP340 challenge and the BIP341 taproot tags (TapLeaf, TapBranch, TapTweak) are built with it. Args: tag_bytes: the domain separation tag, of any length. msg_bytes: the message to hash, of any length. Returns: The 32-byte tagged hash. Raises: RuntimeError: if libsecp256k1 fails, which no input can make it do. Example: >>> from btclib_secp256k1 import hashes >>> hashes.tagged_sha256(b"TapLeaf", b"").hex() '5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb' """ tag_bytes = octets(tag_bytes, "tag") msg_bytes = octets(msg_bytes, "message") output = ffi.new(_HASH_BUFFER_TYPE) if not lib.secp256k1_tagged_sha256( ctx, output, tag_bytes, len(tag_bytes), msg_bytes, len(msg_bytes) ): raise RuntimeError("tagged hashing failed") return ffi.unpack(output, _HASH_SIZE)