encrypt-and-tag
Encrypt and tag an incoming message
Bob wants to send Alice a private message, e.g. the contents of a note, which we'll refer to as the . Bob and Alice are using a "tag hopping" scheme to help with note discovery. Let's assume they've already handshaked to establish a shared secret , from which a sequence of tags can be derived.
Thing | Derivation | Name | Comments |
---|---|---|---|
Given by Alice | (Diversifier) | Remember, in most cases, is sufficient. | |
(Diversified) generator | Remember, when , . | ||
ephemeral secret key | |||
(Diversified) Ephemeral public key | |||
Shared secret, for ciphertext header encryption | TODO: can we use the same ephemeral keypair for both the ciphertext header and the ciphertext? TODO: diversify the ? | ||
h("?", ) | Ciphertext header encryption key | ||
(app_address) | Ciphertext header | ||
ephemeral secret key | |||
(Diversified) Ephemeral public key | |||
Shared secret, for ciphertext encryption | |||
h("?", ) | Incoming data encryption key | ||
Ciphertext | |||
[, , , , ] | Payload |
Alice can learn about her new as follows. First, she would identify the transaction has intended for her, either by observing on-chain herself (and then downloading the rest of the payload which accompanies the tag), or by making a privacy-preserving request to a server, to retrieve the payload which accompanies the tag. Assuming the has been identified as Alice's, and retrieved by Alice, we proceed.
Given that the tag in this illustration was derived from Alice's master key, the tag itself doesn't convey which app_address to use, to derive the correct app-siloed incoming viewing secret key that would enable decryption of the ciphertext. So first Alice needs to decrypt the using her master key:
Thing | Derivation | Name |
---|---|---|
Shared secret, for encrypting the ciphertext header | ||
h("?", ) | Incoming encryption key | |
app_address | App address | |
See derivations above. Use the decrypted app_address. | App-specific incoming viewing secret key | |
Shared secret, for ciphertext encryption | ||
h("?", ) | Ciphertext encryption key | |
Plaintext |
Encrypt and tag an outgoing message
Bob wants to send himself a private message (e.g. a record of the outgoing notes that he's created for other people) which we'll refer to as the . Let's assume Bob has derived a sequence of tags for himself (see earlier).
Note: this illustration uses master keys for tags, rather than app-specific keys for tags. App-specific keys for tags could be used instead, in which case a 'ciphertext header' wouldn't be needed for the 'app_address', since the address could be inferred from the tag.
Note: rather than copying the 'shared secret' approach of Bob sending to Alice, we can cut a corner (because Bob is the sender and recipient, and so knows his own secrets).
Note: if Bob has sent a private message to Alice, and he also wants to send himself a corresponding message:
- he can likely re-use the ephemeral keypairs for himself.
- he can include in the plaintext that he sends to himself, as a way of reducing the size of his (since the will enable him to access all the information in the ciphertext that was sent to Alice).
Note: the violet symbols should actually be orange here.
Thing | Derivation | Name | Comments |
---|---|---|---|
Given by Alice | (Diversifier) | Remember, in most cases, is sufficient. | |
(Diversified) generator | Remember, when , . | ||
ephemeral secret key | |||
(Diversified) Ephemeral public key | |||
h("?", , ) | Header encryption key | This uses a master secret key , which MUST NOT be given to an app nor to an app circuit. However, it can still be given to a trusted precompile, which can handle this derivation securely. | |
(app_address) | Ciphertext header encryption key | ||
ephemeral secret key | |||
(Diversified) Ephemeral public key | |||
h("?", , ) | Outgoing data encryption key | Since is a hardened app-siloed secret key, it may be safely given to the dapp or passed into the app's circuit. | |
Ciphertext | |||
[, , , , ] | Payload |
Alice can learn about her new as follows. First, she would identify the transaction has intended for her, either by observing on-chain herself (and then downloading the rest of the payload which accompanies the tag), or by making a privacy-preserving request to a server, to retrieve the payload which accompanies the tag. Assuming the has been identified as Alice's, and retrieved by Alice, we proceed.
Given that the tag in this illustration was derived from Alice's master key, the tag itself doesn't convey which app_address to use, to derive the correct app-siloed incoming viewing secret key that would enable decryption of the ciphertext. So first Alice needs to decrypt the using her master key:
Thing | Derivation | Name |
---|---|---|
h("?", , ) | ||
app_address | ||
See derivations above. Use the decrypted app_address. | ||
h("?", , ) | ||
Doing this inside an app circuit
Here's how an app circuit could constrain the app-siloed outgoing viewing secret key () to be correct:
The app circuit exposes, as public inputs, an "outgoing viewing key validation request":
Thing | Derivation | Name | Comments |
---|---|---|---|
outgoing_viewing_key_validation_request | app_address: app_address, hardened_child_sk: , claimed_parent_pk: |
The kernel circuit can then validate the request (having been given as a private input to the kernel circuit):
Thing | Derivation | Name | Comments |
---|---|---|---|
Outgoing viewing public key | |||
Copy-constrain with . |
If the kernel circuit succeeds in these calculations, then the has been validated as the correct app-siled secret key for .
Encrypt and tag an internal incoming message
Internal incoming messages are handled analogously to outgoing messages, since in both cases the sender is the same as the recipient, who has access to the secret keys when encrypting and tagging the message.