Relay and receipts
What the relay receives, how the batch is committed, and how a signed receipt makes censorship provable.
- the order's leaf
- proof: sibling hashes
- recomputed on the way to the root
Envelope#
The envelope is the only thing a client sends to the relay.
{
"protocolVersion": 1,
"scheme": 1,
"epochId": 48392,
"ciphertext": "0x…",
"ciphertextHash": "0x…",
"orderCommitment": "0x…"
}
ciphertextHash = keccak256(ciphertext).orderCommitment = keccak256(orderDigest ‖ salt).- Maximum ciphertext size is 4096 bytes.
- The relay rejects any envelope with extra fields, so plaintext metadata cannot ride along by accident.
There is no ticker, side, amount, price or wallet in the envelope.
Why the commitment is public. The settlement contract must be able to check that an order it is asked to settle was in the batch that was fixed before decryption. A leaf that held only the ciphertext hash would not do: the contract cannot verify a decryption, so an operator could commit a junk ciphertext, wait for everyone else's orders to decrypt, and then claim that a freshly written order was the plaintext of that leaf. The commitment binds the plaintext order to the leaf. It is a salted hash, so it reveals nothing about the order. After decryption the matcher rejects any ciphertext whose plaintext does not hash to its commitment.
Merkle leaf and tree#
leaf = keccak256( keccak256( abi.encode(uint64 epochId, uint64 sequence,
bytes32 orderCommitment, bytes32 ciphertextHash) ) )
The double hash keeps leaves and inner nodes in different domains. Inner nodes hash the sorted pair
keccak256(min ‖ max). An unpaired node is promoted unchanged. Leaves are ordered by sequence.
Implementations: KasumiOrderLib.leaf and verifyProof, packages/sdk/src/merkle.ts.
Inclusion receipt#
On acceptance the relay returns an EIP-712 signed receipt.
domain = { name: "Kasumi Relay", version: "1", chainId }
InclusionReceipt(bytes32 orderCommitment, bytes32 ciphertextHash,
uint64 epochId, uint64 sequence, uint64 receivedAt, uint64 cutoff)
It states: the relay accepted this ciphertext for this epoch, at this position, before the cutoff. After
the epoch closes the client fetches a Merkle proof and calls verifyInclusion(receipt, merkleProof, root, expectedRelay). If the receipt signature is valid and the leaf is not under the published root, the result
has censored: true, and the receipt is the evidence.