Luckotto

Demosino

GameDemosino
Playerdemo
Hash tweak

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.

SchemePayload to BIP32 path
  • 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.

Default descriptor is the configured deposit wallet.

HMAC keyhash-tweak
Tweak bytes15
Derived addressPending
Path from descriptor
Pending
Network
Pending
Script type
Pending
HMAC-SHA256
Pending
Child indexes (3 bytes each, big-endian)
Pending
Derivation

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.