(slightly) faster tagged sha256

This commit is contained in:
scgbckbone 2025-06-02 14:00:14 +02:00
parent e209980630
commit e68123caa0
6 changed files with 23 additions and 10 deletions

2
external/libngu vendored

@ -1 +1 @@
Subproject commit 1cccb25ef7736efae4a1de83d5dbdc13a2db0e80
Subproject commit 9a78ad25067eb0615d09df6ebca11047e81e172d

View File

@ -12,6 +12,7 @@ from public_constants import TAPROOT_LEAF_TAPSCRIPT, TAPROOT_LEAF_MASK
from serializations import hash160, ser_compact_size, disassemble, ser_string
from ucollections import namedtuple
from opcodes import OP_RETURN, OP_1, OP_16
from precomp_tag_hash import TAP_TWEAK_H, TAP_LEAF_H
SINGLESIG_AF = (AF_P2WPKH, AF_CLASSIC, AF_P2TR, AF_P2WPKH_P2SH)
@ -40,7 +41,7 @@ def taptweak(internal_key, tweak=None):
# This can be achieved by computing the output key point as:
# Q = P + int(hashTapTweak(bytes(P)))G."
actual_tweak = internal_key if tweak is None else internal_key + tweak
tweak = ngu.secp256k1.tagged_sha256(b"TapTweak", actual_tweak)
tweak = ngu.hash.sha256t(TAP_TWEAK_H, actual_tweak, True)
xo_pubkey = ngu.secp256k1.xonly_pubkey(internal_key)
xo_pubkey_tweaked = xo_pubkey.tweak_add(tweak)
return xo_pubkey_tweaked.to_bytes()
@ -51,8 +52,7 @@ def tapscript_serialize(script, leaf_version=TAPROOT_LEAF_TAPSCRIPT):
return bytes([lv]) + ser_string(script)
def tapleaf_hash(script, leaf_version=TAPROOT_LEAF_TAPSCRIPT):
return ngu.secp256k1.tagged_sha256(b"TapLeaf",
tapscript_serialize(script, leaf_version))
return ngu.hash.sha256t(TAP_LEAF_H, tapscript_serialize(script, leaf_version), True)
class ChainsBase:

View File

@ -9,6 +9,7 @@ from binascii import unhexlify as a2b_hex
from binascii import hexlify as b2a_hex
from utils import keypath_to_str, str_to_keypath, swab32, xfp2str
from serializations import ser_compact_size
from precomp_tag_hash import TAP_BRANCH_H
WILDCARD = "*"
@ -516,8 +517,7 @@ def taproot_tree_helper(scripts):
if isinstance(scripts, Miniscript):
script = scripts.compile()
assert isinstance(script, bytes)
h = ngu.secp256k1.tagged_sha256(b"TapLeaf", chains.tapscript_serialize(script))
h = chains.tapleaf_hash(script)
return [(chains.TAPROOT_LEAF_TAPSCRIPT, script, bytes())], h
left, left_h = taproot_tree_helper(scripts[0].tree)
@ -526,5 +526,6 @@ def taproot_tree_helper(scripts):
right = [(version, script, control + left_h) for version, script, control in right]
if right_h < left_h:
right_h, left_h = left_h, right_h
h = ngu.secp256k1.tagged_sha256(b"TapBranch", left_h + right_h)
h = ngu.hash.sha256t(TAP_BRANCH_H, left_h + right_h, True)
return left + right, h

View File

@ -36,6 +36,7 @@ freeze_as_mpy('', [
'opcodes.py',
'paper.py',
'pincodes.py',
'precomp_tag_hash.py',
'psbt.py',
'pwsave.py',
'queues.py',

View File

@ -0,0 +1,9 @@
# taproot precomputed tag hashes
# SHA256(TapLeaf)
TAP_LEAF_H = b'\xae\xea\x8f\xdcB\x08\x981\x05sKX\x08\x1d\x1e&8\xd3_\x1c\xb5@\x08\xd4\xd3W\xca\x03\xbex\xe9\xee'
# SHA256(TapBranch)
TAP_BRANCH_H = b'\x19A\xa1\xf2\xe5n\xb9_\xa2\xa9\xf1\x94\xbe\\\x01\xf7!o3\xed\x82\xb0\x91F4\x90\xd0[\xf5\x16\xa0\x15'
# SHA256(TapTweak)
TAP_TWEAK_H = b'\xe8\x0f\xe1c\x9c\x9c\xa0P\xe3\xaf\x1b9\xc1C\xc6>B\x9c\xbc\xeb\x15\xd9@\xfb\xb5\xc5\xa1\xf4\xafW\xc5\xe9'
# SHA256(TapSighash)
TAP_SIGHASH_H = b'\xf4\nH\xdfK*p\xc8\xb4\x92K\xf2eFa\xed=\x95\xfdf\xa3\x13\xeb\x87#u\x97\xc6(\xe4\xa01'

View File

@ -20,8 +20,9 @@ from serializations import CTxIn, CTxInWitness, CTxOut, ser_string, COutPoint
from serializations import ser_sig_der, uint256_from_str, ser_push_data
from serializations import SIGHASH_ALL, SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY
from serializations import ALL_SIGHASH_FLAGS, SIGHASH_DEFAULT
from opcodes import OP_CHECKMULTISIG, OP_RETURN
from opcodes import OP_CHECKMULTISIG
from glob import settings
from precomp_tag_hash import TAP_TWEAK_H, TAP_SIGHASH_H
from public_constants import (
PSBT_GLOBAL_UNSIGNED_TX, PSBT_GLOBAL_XPUB, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_WITNESS_UTXO,
@ -2473,7 +2474,8 @@ class psbtObject(psbtProxy):
# merkle root needs to be added to tweak with internal key
# merkle root was already verified against registered script in determine_my_signing_key
tweak += self.get(inp.taproot_merkle_root)
tweak = ngu.secp256k1.tagged_sha256(b"TapTweak", tweak)
tweak = ngu.hash.sha256t(TAP_TWEAK_H, tweak, True)
kpt = kp.xonly_tweak_add(tweak)
sig = ngu.secp256k1.sign_schnorr(kpt, digest, ngu.random.bytes(32))
if inp.sighash != SIGHASH_DEFAULT:
@ -2688,7 +2690,7 @@ class psbtObject(psbtProxy):
out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 32 + (
annex is not None) * 32 + scriptpath * 37, "taproot SigMsg length does not make sense"
fd.seek(old_pos)
sighash = ngu.secp256k1.tagged_sha256(b"TapSighash", msg)
sighash = ngu.hash.sha256t(TAP_SIGHASH_H, msg, True)
return sighash
def make_txn_segwit_sighash(self, replace_idx, replacement, amount, scriptCode, sighash_type):