mirror of
https://github.com/lightning/bolts.git
synced 2024-11-19 01:50:03 +01:00
prop: First draft of the rendez-vous proposal
This commit is contained in:
parent
f642fc7695
commit
388130335e
234
proposals/0001-rendez-vous.md
Normal file
234
proposals/0001-rendez-vous.md
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
1. [Proposal](#org78d4940)
|
||||||
|
1. [Introduction](#orgd0023b1)
|
||||||
|
2. [Overview](#orgdb755c0)
|
||||||
|
3. [Partial Onion Packet Creation](#orgcaa6be5)
|
||||||
|
4. [Sending a Rendez-vous Payment](#orgce4245c)
|
||||||
|
5. [Processing at the Rendez-vous Node](#orgb7aec92)
|
||||||
|
6. [Signalling](#orgf8a3390)
|
||||||
|
1. [Invoice signalling](#orgeec1817)
|
||||||
|
2. [Rendez-vous node signalling](#orga7e7d24)
|
||||||
|
7. [Common Questions](#org5952639)
|
||||||
|
1. [Why nest the RV onion inside the outer onion and not inline?](#org335c922)
|
||||||
|
2. [Why prefill with a known pseudo-random stream?](#org93dff5e)
|
||||||
|
|
||||||
|
|
||||||
|
<a id="org78d4940"></a>
|
||||||
|
|
||||||
|
# Proposal
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orgd0023b1"></a>
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Use-cases:
|
||||||
|
|
||||||
|
- Provide <span class="underline">recipient-anonymity</span> by hiding the second part of the route in the
|
||||||
|
partial onion.
|
||||||
|
- Force a payment to go through a specific intermediary. This allows the
|
||||||
|
intermediary to <span class="underline">witness a payment</span>, or <span class="underline">control its resolution</span>. Examples
|
||||||
|
of where this might be useful include:
|
||||||
|
- An accountant server gets to witness all payments without any need to
|
||||||
|
trust it.
|
||||||
|
- A game server can use rendez-vous invoices to receive two incoming
|
||||||
|
payments, hold onto them and release the loser's payment to the winner
|
||||||
|
once the game is decided. The winner is masqueraded from both the game
|
||||||
|
server as well as the other players.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orgdb755c0"></a>
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The goal of this proposal is to allow a network participant, to create a
|
||||||
|
partial onion that can then be completed to a complete onion by a sender that
|
||||||
|
then describes the entire path from sender to recipient. We will refer to the
|
||||||
|
sender node as `S`, the recipient as `R` and the node at which the partial
|
||||||
|
onion starts, and the prepended prefix ends, as rendez-vous node `RV`.
|
||||||
|
|
||||||
|
The construction relies on the *partial onion*, which describes the path from
|
||||||
|
`RV` to `R`, being included as the per-hop payload in the *outer routing
|
||||||
|
onion* from `S` to `RV`. In order to be able to transfer the partial onion in
|
||||||
|
the outer onion it will require some preprocessing, since both inner partial
|
||||||
|
and outer routing onion have a fixed size of 1366 bytes.
|
||||||
|
The preprocessing consists of generating the partial onion in such a way that
|
||||||
|
it can be easily compressed, and thus fits into the outer onion's payload.
|
||||||
|
|
||||||
|
The general structure of the routing onion is as follows:
|
||||||
|
|
||||||
|
![img](images/rendez-vous-onion-structure.png)
|
||||||
|
|
||||||
|
The middle part consisting of a number of *payloads* and padded with the
|
||||||
|
*unused space* is called the routing info. The construction described below
|
||||||
|
allows the partial onion creator to zero out the unused space, and fill it
|
||||||
|
with a pseudo-random stream that can easily be generated at `RV`, allowing it
|
||||||
|
to re-generate the original onion from the compressed representation.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orgcaa6be5"></a>
|
||||||
|
|
||||||
|
## Partial Onion Packet Creation
|
||||||
|
|
||||||
|
The partial onion creator generates an onion like described in
|
||||||
|
[BOLT04][bolt04]. After initializing the packet with the ChaCha20-based
|
||||||
|
CSPRNG, some part of the unused space is then re-initialized with a `prefill`
|
||||||
|
which cancels out the encryption layers applied by each processing node.
|
||||||
|
|
||||||
|
In order to zero out the encryption layers that each node would apply to the
|
||||||
|
partial onion the partial onion creator needs to initialize the part of the
|
||||||
|
unused space with the `xor` of the stream that each node applies when
|
||||||
|
processing the onion. This is complicated slightly by the fact that each node
|
||||||
|
also shifts the packet, meaning that in order for the encryption to cancel out
|
||||||
|
a different section of the encryption stream needs to be applied. The logic
|
||||||
|
for this can however be extracted from the [filler
|
||||||
|
generation][bolt04-filler]. The following code generates the neceassry filler
|
||||||
|
for the unused space:
|
||||||
|
|
||||||
|
static bool generate_prefill(void *dst, size_t dstlen,
|
||||||
|
const struct sphinx_path *path,
|
||||||
|
struct hop_params *params)
|
||||||
|
{
|
||||||
|
u8 stream[2 * ROUTING_INFO_SIZE];
|
||||||
|
u8 key[KEY_LEN];
|
||||||
|
size_t fillerStart, fillerSize;
|
||||||
|
|
||||||
|
memset(dst, 0, dstlen);
|
||||||
|
for (int i = 0; i < tal_count(path->hops); i++) {
|
||||||
|
if (!generate_key(&key, RHO_KEYTYPE, strlen(RHO_KEYTYPE),
|
||||||
|
¶ms[i].secret))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
generate_cipher_stream(stream, key, sizeof(stream));
|
||||||
|
|
||||||
|
/* Sum up how many bytes have been used by previous hops,
|
||||||
|
* that gives us the start in the stream */
|
||||||
|
fillerSize = 0;
|
||||||
|
for (int j = 0; j < i; j++)
|
||||||
|
fillerSize += sphinx_hop_size(&path->hops[j]);
|
||||||
|
fillerStart = ROUTING_INFO_SIZE - fillerSize - dstlen;
|
||||||
|
|
||||||
|
/* Apply this hop's prefill */
|
||||||
|
xorbytes(dst, dst, stream + fillerStart, dstlen);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
The main differences to the [filler generation][bolt04-filler] are that the
|
||||||
|
generated stream always has the same length whereas the filler length depends
|
||||||
|
on the hop position, and that all hops are generated, unlike the filler which
|
||||||
|
skips the last hop.
|
||||||
|
|
||||||
|
If the unused space is initialized with the resulting prefill stream it is
|
||||||
|
guaranteed to cancel out the encryption layers and result in a zeroed out
|
||||||
|
middle part of the partial onion which can then be skipped when serializing.
|
||||||
|
|
||||||
|
The length of this prefill can be any range from 0 to the full unused
|
||||||
|
space. The maximum size of the unused space depends on the effective payload,
|
||||||
|
i.e., sum of the per-hop payloads and their respective HMACs. A legacy onion
|
||||||
|
with 5 hops would have an effective payload of 5\*65 bytes, leaving 975 bytes
|
||||||
|
unused space.
|
||||||
|
|
||||||
|
Notice that it is desirable to initialize less than the full unused space in
|
||||||
|
order to hide the length of the effective payload from `RV`.
|
||||||
|
|
||||||
|
After applying this initialization the partial onion would look as follows:
|
||||||
|
|
||||||
|
![img](images/rendez-vous-zeroed.png)
|
||||||
|
|
||||||
|
This would be the onion leading from `RV` to `R`, and would also be the onion
|
||||||
|
that is presented to `RV+1`, i.e., the first node after `RV`. Since this would
|
||||||
|
leak the information that `RV` was a rendez-vous node to `RV+1` we further
|
||||||
|
obfuscate the partial onion by also filling it with a ChaCha20 stream. For
|
||||||
|
this purpose the partial onion creator generates a key using the [key
|
||||||
|
generation algorithm][key-gen], the `ephkey` from the partial onion and the
|
||||||
|
key type `prefill` (`0x70726566696c6c`). This key is then used to generate a
|
||||||
|
ChaCha20 stream matching the prefill-length, and applied via `xor` to the
|
||||||
|
prefill. The result is a partial onion which, once fully wrapped, has the
|
||||||
|
ChaCha20 stream in the place of the prefill.
|
||||||
|
|
||||||
|
The partial onion is then compressed by simply omitting the prefill, since
|
||||||
|
that can be re-generated at `RV` once it processes the payment.
|
||||||
|
|
||||||
|
![img](images/rendez-vous-compressed.png)
|
||||||
|
|
||||||
|
[bolt04]: <https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md>
|
||||||
|
[bolt04-filler]: <https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#filler-generation>
|
||||||
|
[key-gen]: <https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#key-generation>
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orgce4245c"></a>
|
||||||
|
|
||||||
|
## Sending a Rendez-vous Payment
|
||||||
|
|
||||||
|
Upon receiving a partial onion the sender `S` creates the outer onion,
|
||||||
|
carrying the payment and the partial onion from itself to the rendez-vous node
|
||||||
|
`RV`. This is achieved by searching for a path from `S` to `RV`, building
|
||||||
|
the outer onion, and including the partial onion in the per-hop payload
|
||||||
|
destined for `RV`.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orgb7aec92"></a>
|
||||||
|
|
||||||
|
## Processing at the Rendez-vous Node
|
||||||
|
|
||||||
|
Upon receiving an incoming HTLC and associated onion `RV` extracts its
|
||||||
|
payload. If the payload contains a compressed it splits off the HMAC at the
|
||||||
|
end, computes how many bytes it needs to prefill, and generates the prefill
|
||||||
|
key using the included ephemeral key `ephkey` (not the ephemeral key from the
|
||||||
|
outer onion).
|
||||||
|
|
||||||
|
The prefill is then used to complete the partial onion, and the partial onion
|
||||||
|
can be serialized and forwarded to the next hop.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orgf8a3390"></a>
|
||||||
|
|
||||||
|
## Signalling
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orgeec1817"></a>
|
||||||
|
|
||||||
|
### Invoice signalling
|
||||||
|
|
||||||
|
|
||||||
|
<a id="orga7e7d24"></a>
|
||||||
|
|
||||||
|
### Rendez-vous node signalling
|
||||||
|
|
||||||
|
|
||||||
|
<a id="org5952639"></a>
|
||||||
|
|
||||||
|
## Common Questions
|
||||||
|
|
||||||
|
|
||||||
|
<a id="org335c922"></a>
|
||||||
|
|
||||||
|
### Why nest the RV onion inside the outer onion and not inline?
|
||||||
|
|
||||||
|
With a similar construction it could be possible to amend the incoming onion
|
||||||
|
in such a way that it becomes a valid onion for the send part of the path, and
|
||||||
|
swapping out the ephemeral key. This is what the [previous proposal][prev] was
|
||||||
|
trying to achieve, however the nesting method is simpler to implement and
|
||||||
|
has the same space requirements. It is possible to have the sender stash the
|
||||||
|
partial onion in the unused space in the outer onion and then having `RV`
|
||||||
|
overwrite the tail of the incoming onion with the stream, but it is slightly
|
||||||
|
more awkward.
|
||||||
|
|
||||||
|
[prev]: <https://github.com/lightningnetwork/lightning-rfc/wiki/Rendez-vous-mechanism-on-top-of-Sphinx>
|
||||||
|
|
||||||
|
|
||||||
|
<a id="org93dff5e"></a>
|
||||||
|
|
||||||
|
### Why prefill with a known pseudo-random stream?
|
||||||
|
|
||||||
|
We want to hide the fact that `RV` was a rendez-vous node from `RV+1`, hence
|
||||||
|
we can't leave the prefill zeroed out.Instead of generating the prefill in
|
||||||
|
such a way that the partial onion contains a pseudo-random stream we could
|
||||||
|
just zero it out and then re-process the onion as if `RV` were in the route
|
||||||
|
twice. However having the partial onion creator generate the prefill with the
|
||||||
|
pseudo-random stream seems like a better tradeoff with respect to
|
||||||
|
computational load on `RV`.
|
||||||
|
|
BIN
proposals/images/rendez-vous-compressed.png
Normal file
BIN
proposals/images/rendez-vous-compressed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
proposals/images/rendez-vous-onion-structure.png
Normal file
BIN
proposals/images/rendez-vous-onion-structure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
BIN
proposals/images/rendez-vous-zeroed.png
Normal file
BIN
proposals/images/rendez-vous-zeroed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Loading…
Reference in New Issue
Block a user