SOME CATS is a scheme to send 16-byte transaction memos in 2-out transactions using Carrot. SOME CATS memos are:
- Encrypted - Memos are encrypted to the receiver, optionally visible to the sender as well
- Indistinguishable - Transactions containing a SOME CATS memo are indistinguishable from normal Carrot transactions
- Available on-chain - The memo will always be available on-chain as long as its associated transaction is
- Receiver agnostic - The receiver doesn't need to support SOME CATS to spend funds sent in a SOME CATS transaction, so long as they support the Carrot addressing protocol
See the Carrot notation section.
We also introduce two functions: cipher(k, p)
and decipher(k, c)
which perform symmetric block cipher operations on 16-byte (128-bit) blocks. One implementation we could use in practice is Twofish. They have the relationship:
decipher(k, cipher(k, p)) = p
cipher(k, decipher(k, c)) = c
Given 16-byte message m
and receiver address (Ksj, Kvj)
:
- If the sender wants to remember the memo, she sets
anchorrecv = SecretDerive("somecats sender-view memo anchor" || svb || input_context)
, otherwise she setsanchorrecv = RandBytes(16)
- Sender derives the memo cipher secret
smemo = SecretDerive("somecats cipher secret" || anchorrecv || input_context || Ksj || Kvj || pid)
- Sender sets
mc = cipher(smemo, m)
- Sender constructs external enote to the receiver
E1
withanchor = anchorrecv
, instead of the regularanchor = RandBytes(16)
- Sender constructs internal selfsend enote
E2
withanchorenc = mc
, skipping regular anchor encryption - Sender constructs transaction containing enotes
E1
andE2
- During the enote scan process, while checking against Janus attacks, the receiver will decrypt
anchor
- Receiver derives the memo cipher secret
smemo = SecretDerive("somecats cipher secret" || anchor || input_context || Ksj || Kvj || pid)
- Receiver deciphers the memo
m = decipher(smemo, anchorencother)
, whereanchorencother
is the encrypted anchor on the other enote
If the sender chose to derive anchor
deterministically, then they can obtain anchor = SecretDerive("somecats sender-view memo anchor" || svb || input_context)
, replacing step 1.