Contracts, circuits & frontend 👉 https://github.com/kevincharm/i_lost_my_eth_in_a_boating_accident
Deployed SunkETH contract: https://sepolia.etherscan.io/address/0x46cfe55bf2e5a02b738f5bbdc1bdee9dd22b5d39
Example reminting transaction with ZK proof-of-burn: https://sepolia.etherscan.io/tx/0xda33a40dc4c9cd1aa0e3881db9e5fcb580ed0f078d27cb030bd796ad1974d3fb
Example unspendable address: https://sepolia.etherscan.io/address/0xe175aB294bCA5cC767Ef8Cf58A0F287C7f43c342
SunkETH works like WETH, but supercharged with zero-knowledge wormholes (https://eips.ethereum.org/EIPS/eip-7503). Using some cryptographic tricks and with the help of ZKPs, we can create private transfers that are indistinguishable from regular transfers.
At the heart of zero-knowledge wormholes is the verifiably-unspendable address. We can define an unspendable address by taking the preimage resistance property of keccak256 s.t. given random number $r$ and $keccak256(x) = r$, we cannot feasibly compute $x$.
Importantly, we need to ensure that $r$ is truly random. So if we take another hash function different to keccak256 (e.g. sha256) and treat it as a random oracle, then we cannot know $x$ where $keccak256(x) = sha256(s)$. Therefore address $A_u = keccak256(x) = sha256(s)$ is unspendable.
Using ZKPs, we can prove knowledge of $s$ without revealing $s$ and only revealing $A_u = sha256(s)$. This means we can prove that we transferred funds to a verifiably-unspendable address, and it would be safe to *re-mint* the transferred amount, at a new arbitrary address.
We use aragon's noir-trie-proofs (https://github.com/aragonzkresearch/noir-trie-proofs) circuits to create state and storage proofs, while hiding the storage key, thus never revealing $A_u$. The state proof is verified against a state root, which is extracted from an RLP-encoded block header that corresponds to a recent known blockhash (it can be any block after burning tokens to an unspendable address).
The state root proves the SunkETH contract account state, which is RLP-encoded data that includes the account's storage root. We privately prove that the storage root is correct using a storage proof as a private input to our circuit - this hides the storage key, which hides unspendable address.