Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monero addresses break forward-secrecy #649

Open
kayabaNerve opened this issue Jan 24, 2025 · 2 comments
Open

Monero addresses break forward-secrecy #649

kayabaNerve opened this issue Jan 24, 2025 · 2 comments
Labels
discussion This requires discussion feature New feature or request monero An issue with the Monero library/integration

Comments

@kayabaNerve
Copy link
Member

Anyone who obtains a Monero address can, with a quantum computer, recover the private view key for a Monero address. As Serai is a public network, it serves as a repository of addresses which can broken later.

The solution to this is not to collect addresses but fully-derived outputs, single-use, which we can send to.

The design goals are for this scheme not to exceed the length of an existing address, or be comparable to. Under the current Monero (not CARROT), it would be possible to specify R, view_tag, Hs(8Ra || i), spend_key, payment_id_xor and derive the commitment mask, amount encryption to form a complete output. This would be 105 bytes, not 64 however (97 if we ignore payment_id_xor). This prevents recovering the view key, and the spend key may be that for a subaddress, offering uniformity there without an inefficient scan process.

This doesn't work in practice as the output would be bound to an output index and Serai does not guarantee output position.

cc @jeffro256 for how this could work with CARROT

@kayabaNerve kayabaNerve added discussion This requires discussion feature New feature or request monero An issue with the Monero library/integration labels Jan 24, 2025
@jeffro256
Copy link
Contributor

jeffro256 commented Jan 24, 2025

Here's a refund address sketch, modified from what we talked about earlier:

Let the initial transaction that sends funds be $T_i$ and the refund transaction be $T_r$. Let $O'$ be the sum of all the output pubkey rerandomizations in $T_i$. For a specific enote in $T_i$ with a onetime address $K^i_o$ and sender-receiver secrets $s_{sr}$ and $s_{sr}^{ctx}$, let the refund address spend pubkey be:

$$K_s^r = O' + H_n(\text{"Carrot refund address"} || s^{ctx}_{sr} || K^i_o || O')$$

Then, to send a refund in $T_r$, the refunder creates an enote, setting the output pubkey to

$$K^r_o = K^r_s + H_n(\text{"Carrot refund input context extension"} || input\_context) G$$

The refunder then recalculates a refund sender-receiver contextualized secret

$$s^r_{sr} = H_{32}(\text{"Carrot refund sender-receiver secret"} || s_{sr} || input\_context || D_e)$$

and uses that to derive $k_a$ and $m_a$ to open the amount commitment for the new enote. The view tag and Janus anchor can be filled with random bytes.

To scan the refund transaction, the sender adds $K^r_s$ to a refund address map, pointing to $s_{sr}$ of the original enote. For each enote on-chain the refundee calculates

$$K' = K_o - H_n(\text{"Carrot refund input context extension"} || input\_context) G$$

and checks if $K'$ is in their refund map. If so, they attempt to recompute the amount commitment with $s_{sr}$ and then can mark the output as owned.

To provide a refund proof to a third party, one can simply provide the initial sender-receiver secret $s_{sr}$ and the TXIDs of $T_i$ and $T_r$.

The original sender does not need to provide any special information in the transaction. They just need to deterministically derive output pubkey rerandomizations. The output pubkey rerandomizations should not be malleable to the SA/L proof. In other words, in order to malleate the output pubkey rerandomizations, knowledge of the opening of the spent onetime address must be required and the SA/L proof resigned, otherwise a mallicious actor could burn refund address funds. This scheme technically allows for sending a refund to the same refundee multiple times on-chain, but it would be trivially distinguishable if this happened, so refunds should ideally only be sent once. This scheme, like subaddresses currently, can be implemented as O(1) in terms of the number of refund addresses created. I think it's okay, but I'll have to think more to determine whether there's a Janus attack vector here. By default, the refunds are not recoverable if the wallet cache is lost since the refundee will forget the $anchor_{norm}$ value used in $T_i$, and thus $s_{sr}$. However, if the refundee contacts the refunder off-chain and requests $s_{sr}$, as provided in the "refund proof", then the refundee would be able to recover the funds even if their wallet cache was lost.

@kayabaNerve
Copy link
Member Author

kayabaNerve commented Jan 25, 2025

This would have to work without an initial transaction. Someone swapping from BTC to XMR should be able to specify an XMR output without publishing their view-key. That's why I mentioned tevador's scheme. Any scheme, not explicitly a return scheme, where the recipient can send a one-time 'address' to the sender (no further interaction).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion This requires discussion feature New feature or request monero An issue with the Monero library/integration
Projects
None yet
Development

No branches or pull requests

2 participants