Parameters.

hash
keccak256
n
32 bytes
w
16
chains
67: 64 for the message, 3 for the checksum
security
128 bits against a quantum search, 256 classical
chaining function
keccak256(pubSeed ‖ c ‖ j ‖ x)
commitment
keccak256(pubSeed ‖ tip₀ ‖ … ‖ tip₆₆)
account address
CREATE2 over the init code holding the commitment
trusted setup
none
proof system
none

Measured, not estimated.

  • 80,271gas to verify a signature, call and memory included
  • 195,542gas to open an account, spend it and close it, before calldata
  • 2,144bytes of signature, carried as calldata
  • 0bytes of code left at a spent address
  • 0events emitted by any contract here
  • 53tests, including a search for a forgeable second message
  • 21 / 21deliberate faults injected into the contracts that the tests caught
  • 3implementations, in Solidity, Python and JavaScript, agreeing byte for byte

What this does not do: it does not hide the amount, and it does not hide that a transfer happened. It unlinks an address from the person holding it and keeps that unlinking true after the curves fall. Anything stronger needs a proof system that is itself hash based, and that is a different piece of work.

One constraint worth saying out loud. A one time key that signs two different messages is a broken key. The client refuses to sign a position twice, and the reusable vault reads its position from the chain rather than from local state, but the rule is real and it is the price of leaving the curve behind.