Open AaronFeickert opened 10 months ago
Note the correctness and consistency of the sender-encrypted data (like that of existing recipient-encrypted data) cannot be checked by the network. This means that if a user does not wish to have the data included, it can simply encrypt empty or junk data of the expected length.
This doesn't change the guarantees that payment proofs provide, however. If junk or incorrect sender-encrypted data were decrypted during payment proof verification, the verification would fail.
Interestingly, this could in certain cases replace payment proofs. Payment proofs reveal coin information (value, memo, and recipient address) to the verifier, but also assert that the prover had spend authority for the transaction that created the coin. If the verifier doesn't care about the spend authority assertion, but only the coin information, it could simply ask the prover to provide k_disc
without an accompanying payment proof. This is much easier for the prover to produce than a full payment proof.
Currently, it's not possible for the sender of a Spark transaction to recover certain transaction information unless it caches coin nonces locally. This information includes recipient addresses and memos. It's possible to include this in a way that would ensure senders can obtain these details when restoring a wallet, and would also simplify payment proofs significantly.
One approach would be to encrypt coin nonces and recipient addresses (without the encrypted diversifier) using a key derived from coin public data and the sender's full view key.
For full view key component
s_2
and coin serial commitment,S
, we can define the disclosure keyk_disc = KDF(s_2, S)
for a key derivation functionKDF
. Given a stream cipher keyed withk_disc
, the sender encrypts the tuple(k, Q_1, Q_2)
. Herek
is the coin nonce andQ_1, Q_2
are two of the components of the recipient address.When the user wishes to restore a wallet or otherwise scan using the full view key, it uses the full view key already to derive incoming coin linking tags, which are used to determine when the coin is later spent. On such detection of a spend, the user would derive
k_disc
and use it to decrypt the tuple. It then usesk
andQ_1
to derive the recipient AEAD keyk_aead
and decrypt the recipient data, which includes the coin memom
, the valuev
, and the componentd
of the recipient address.When the user wishes to produce a payment proof, it follows the approach in the Spark preprint. However, it no longer sends the tuple
(k, d, Q_1, Q_2)
with the proof; instead, it sendsk_disc
. Since this key is derived from the user's full view key uniquely using a KDF, this does not leak information about other coins. The verifier uses the key to decrypt(k, Q_1, Q_2)
, and then continues with proof verification as usual.Encryption of this additional data can use a fixed (zero) initialization vector and does not require an authentication tag, so encryption using a stream cipher means each coin requires an additional 96 bytes of data included. While the sender could provide a payment proof verifier with a different key than
k_disc
and obtain different(k, Q_1, Q_2)
, payment proof security guarantees still apply and cannot be used to fool the verifier.