Deterministic Bitcoin addresses from string payloads.
Hash tweak turns a payload into five non-hardened BIP32 child indexes below a supplied BIP86 Taproot descriptor, then encodes the derived public key as a Taproot address.
- HMAC-SHA256 keyed with hash-tweak
- first 15 bytes are kept
- five 3-byte child indexes are derived
- final child public key becomes a P2TR address
Hash tweak calculator
Convert a string payload and BIP86 descriptor into a deterministic Taproot Bitcoin address.
How hash tweak maps payloads to addresses
The payload is interpreted as a UTF-8 string. The HMAC secret is the fixed string hash-tweak. The first 15 bytes of the HMAC are split into five consecutive 3-byte groups, each read as an unsigned big-endian integer.
digest = HMAC_SHA256(key="hash-tweak", message=utf8(payload)) tweak = digest[0:15] path = [ uint24be(tweak[0:3]), uint24be(tweak[3:6]), uint24be(tweak[6:9]), uint24be(tweak[9:12]), uint24be(tweak[12:15]) ] child = taproot_descriptor_account / path[0] / path[1] / path[2] / path[3] / path[4] address = p2tr(xonly(child.publicKey))
Every child index is between 0 and 16,777,215, so the path is entirely non-hardened and can be derived from the descriptor account alone. The calculator reports the path relative to the supplied descriptor account.
Luckotto deposit addresses use this same scheme with a payload that includes the partner payout address, the player's secret identifier, the Luckotto minimum round number, and the selected ticket tiles. Because the identifier is secret, only the player who holds it (and their partner) can re-derive that ticket's address here.