Title: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: BTCW on January 15, 2024, 09:33:16 PM [Addition, the problem was solved down here (https://bitcointalk.org/index.php?topic=5481697.msg63513705#msg63513705)]
Let's begin with this private key Code: 0000000000000000000000000000000000000000000000000000000000000001 Using any good old tool, bitcoinutils included, it gives us Code: Private key compressed (WIF): KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn I won't go into legacy or nested segwit here, but I would like to mention how we easily derive the native segwit public address using the HASH160 compressed Code: bitcoinutils.bech32.encode('bc',0,bytes.fromhex('751e76e8199196d454941c45d1b3a323f1433bd6')) (Likewise, we can produce the segwit bech32 (P2WSH) address by using the single SHA256 of the compressed public key to get bc1qpac4ht6afshdx2tctnhjnetz7u6g3j9zhwwmc4cqkdsa2jumq42qd3drf7; another thread.) However, here is where I need your help. I know that the P2TR address corresponding to this private key and its witness program are Code: Tweaked Taproot public address (P2TR): bc1pmfr3p9j00pfxjh0zmgp99y8zftmd3s5pmedqhyptwy6lm87hf5sspknck9 since I can quickly arrive at them using bitcoinutils (https://github.com/karask/python-bitcoin-utils) I can furthermore reproduce and verify it with: Code: bitcoinutils.bech32.encode('bc',1,bytes.fromhex('da4710964f7852695de2da025290e24af6d8c281de5a0b902b7135fd9fd74d21')) However, I fail to reverse how bitcoilutils does it. Specifically, this function from here (https://github.com/karask/python-bitcoin-utils/blob/master/bitcoinutils/utils.py#L272) that generates the tweaked public key... Code: def tagged_hash(data: bytes, tag: str) -> bytes: ... gives me a headache. I don't see it. How do you go from the 32-byte x-only public address to that witness program? In other words, how do I reproduce this transformation in Python (without relying on bitcoinutils as a mystery box library)? Code: Input: 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 Need your help! I'm not sure what the library uses as its standard "TapTweak", and I get confused by bitcoinutil's nested (pun intended) code. How do we use hashlib only and arrive at the same tweaked witness program, and thus the identical P2TR public address? I am very well aware you are allowed to use whatever as "TapTweak". Can we, however, simply reproduce the "library recipe"? What is its standard "TapTweak," and how to arrive at this public address, given the data above, using simple Python? Many thanks. Title: Re: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: achow101 on January 16, 2024, 01:21:22 AM Have you tried reading the BIP? https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs
Title: Re: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: BTCW on January 16, 2024, 09:33:29 AM Have you tried reading the BIP? https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs Many times, yes. It is pretty technical and a tad vague regarding the exact code. I tried this pseudocode Code: A tagged hash is: SHA256( SHA256("TapTweak") || as so: Code: taptweek_hash1 = hashlib.sha256('TapTweak'.encode()).hexdigest() No luck, yet. How does bitcoinutils do it? Title: Re: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: pooya87 on January 16, 2024, 12:27:21 PM Code: A tagged hash is: SHA256( SHA256("TapTweak") || Code: SHA256("TapTweak")=e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9 Title: Re: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: BTCW on January 16, 2024, 01:08:45 PM Code: A tagged hash is: SHA256( SHA256("TapTweak") || Code: SHA256("TapTweak")=e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9 Gotcha, the only problem is that Code: hashlib.sha256(bytes.fromhex('e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9' + 'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9' + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')).hexdigest() does not give Code: da4710964f7852695de2da025290e24af6d8c281de5a0b902b7135fd9fd74d21 In other words, we cannot yet reproduce the bitcoinutils' method. (Not only bitcoinutils; several libraries give the same result.) Edit/addition - for reference - and what we aim to reproduce: Code: >>>bitcoinutils.keys.PrivateKey.from_wif('KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn').get_public_key().get_taproot_address().to_string() Title: Re: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: pooya87 on January 16, 2024, 04:28:28 PM Code: hashlib.sha256(bytes.fromhex('e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9' + 'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9' + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')).hexdigest() does not give Code: da4710964f7852695de2da025290e24af6d8c281de5a0b902b7135fd9fd74d21 Code: t = SHA256(SHA256("TapTweak") | SHA256("TapTweak") | pub_bytes) t*G is EC point multiplication (just like you'd get pubkey from a private key) + is EC point addition. Title: Re: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: BTCW on January 16, 2024, 04:41:35 PM Code: hashlib.sha256(bytes.fromhex('e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9' + 'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9' + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')).hexdigest() does not give Code: da4710964f7852695de2da025290e24af6d8c281de5a0b902b7135fd9fd74d21 Code: t = SHA256(SHA256("TapTweak") | SHA256("TapTweak") | pub_bytes) t*G is EC point multiplication (just like you'd get pubkey from a private key) + is EC point addition. So, in Python? Title: Re: Need help reversing bitcoinutils "tagged_hash" to generate Taproot addresses Post by: BTCW on January 17, 2024, 04:14:38 PM Think I nailed it!
I don't think such concrete Python code has been published elsewhere; correct me if I'm wrong. Anyways, here we go. Let's start with some imports and two functions: Code: import hashlib, base58, bitcoinutils.bech32 And in action: Code: seed = '0000000000000000000000000000000000000000000000000000000000000001' Tweaked Taproot demystified - mission accomplished - the output is the desired Taproot public address! Code: bc1pmfr3p9j00pfxjh0zmgp99y8zftmd3s5pmedqhyptwy6lm87hf5sspknck9 Yay. Thank you for all your support. This was the least user-friendly address generation code thus far :) |