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.