diff --git a/external/libngu b/external/libngu index 1cccb25e..9a78ad25 160000 --- a/external/libngu +++ b/external/libngu @@ -1 +1 @@ -Subproject commit 1cccb25ef7736efae4a1de83d5dbdc13a2db0e80 +Subproject commit 9a78ad25067eb0615d09df6ebca11047e81e172d diff --git a/shared/chains.py b/shared/chains.py index 192c7588..b5d0f477 100644 --- a/shared/chains.py +++ b/shared/chains.py @@ -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: diff --git a/shared/desc_utils.py b/shared/desc_utils.py index 2444882c..2a326297 100644 --- a/shared/desc_utils.py +++ b/shared/desc_utils.py @@ -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 \ No newline at end of file diff --git a/shared/manifest.py b/shared/manifest.py index 34d23d72..7a2e4314 100644 --- a/shared/manifest.py +++ b/shared/manifest.py @@ -36,6 +36,7 @@ freeze_as_mpy('', [ 'opcodes.py', 'paper.py', 'pincodes.py', + 'precomp_tag_hash.py', 'psbt.py', 'pwsave.py', 'queues.py', diff --git a/shared/precomp_tag_hash.py b/shared/precomp_tag_hash.py new file mode 100644 index 00000000..6c8e6281 --- /dev/null +++ b/shared/precomp_tag_hash.py @@ -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' \ No newline at end of file diff --git a/shared/psbt.py b/shared/psbt.py index fcc37f54..8dce53bb 100644 --- a/shared/psbt.py +++ b/shared/psbt.py @@ -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):