Lamport signatures and other CAT tricks

This requires separate pushes of 0 or 1 for each level of each merkle tree to decide what branch you want. I don’t think you can do better than that with just CAT, but if you had DIVMOD (takes s1, s2 from the stack, pushes int(s1/s2) then s1%s2 onto the stack; cf elements’ OP_DIV64) you could provide a leaf number, and execute something like:

ROT ROT 2 DIVMOD 2SWAP ROT IF SWAP ENDIF CAT HASH160

to combine a path towards the root (starting stack is: [path, n, hash]). It’s 6B more script per level, vs 2 bytes less witness data per level, so unlikely to be interesting unless you’re running into stack size limits, or also adding a looping construct

You could also consider an OP_STR_LESSTHAN that compares two byte vectors, and code it as STR_LESSTHAN NOTIF SWAP ENDIF CAT HASH160, and construct the merkle tree with an implicit order.

I think your script’s idea is:

  • to create a single-use pubkey, you generate 20 byte commitments.
  • for each byte commitment, you create a merkle tree where the leaves are “nonce ++ byte”
  • the single-use pubkey is then the hash of the concatenation of its commitment roots

To verify a signature, you then:

  • for each byte of the message hash, you reveal the path to the nth commitment for the pubkey
  • you combine the commitment roots to produce the single use pubkey
  • you check the pubkey is what you expect
  • you’re left with the msg hash on the stack, which you might then verify by constructing a signature verification with R=P=G, or could compare directly with the result of <x> TXHASH HASH160 or similar.

There’s a couple of stack optimisations you could do (you’ve got a TOALT immediately followed by a FROMALT, eg), but I don’t think there’s much else to be done, without some sort of looping construct.