Skip to content

Formats and hashing

All hashes are SHA-256. ‖ is byte concatenation. Integers are noted with their byte order.

LMOTS_SHA256_N24_W8 from SP 800-208.

n 24 bytes
w 8 bits
p 26 chains
Signature 4 + 24 + 26 × 24 = 652 bytes
Key generation about 6,600 hashes

Chain start for chain i: x_i = H(I ‖ u32be(q) ‖ u16be(i) ‖ 0xff ‖ SEED)[..24], then 255 steps of H(I ‖ u32be(q) ‖ u16be(i) ‖ u8(j) ‖ tmp)[..24]. Public key: H(I ‖ u32be(q) ‖ 0x8080 ‖ y_0 ‖ … ‖ y_25)[..24].

"QARK-VAULT-v1" 13 bytes
program id 32
vault address 32
q u32 big-endian
next_key 24
mint 32
destination 32
amount u64 little-endian

The program recomputes the candidate public key from sig and this message at leaf q, and accepts if the first 24 bytes equal the stored key.

commitment = sha256("QARK-LIFEBOAT-v1" ‖ I ‖ K)

I is the 16-byte key id and K the 24-byte LM-OTS public key, both at q = 0.

leaf = sha256(holder_pubkey ‖ commitment ‖ u64le(balance))
node = sha256(min(a, b) ‖ max(a, b)) // sorted pair, byte order
  • Leaves are sorted before building, so the root does not depend on input order.
  • An odd node at the end of a level is carried up unchanged.
  • Holders without a Lifeboat use 32 zero bytes as commitment.
  • An empty coin has a root of 32 zero bytes.
  • Balances are summed per owner across all their token accounts of the coin.

A proof is the list of sibling hashes from leaf to root. Verify by folding node over the proof starting from the leaf.