diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 205772803..e009ba9f2 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -2417,6 +2417,8 @@ A receiving node: - MUST return an error in the `update_fail_htlc` sent to the link which originally sent the HTLC, using the `failure_code` given and setting the data to `sha256_of_onion`. + - SHOULD add a random delay before sending `update_fulfill_htlc`, + `update_fail_htlc`, `update_fail_malformed_htlc`. #### Rationale @@ -2439,6 +2441,20 @@ such detection is left as an option. Nodes inside a blinded route must use `invalid_onion_blinding` to avoid leaking information to senders trying to probe the blinded route. +Receiving nodes should wait for a random amount of time before responding to +incoming HTLCs with `update_fulfill_htlc` / `update_fail_malformed_htlc` / +`update_fail_htlc` to impair the capabilities of a potential adversary trying +to deanonymize them based on message timing analysis. The delay distribution +and parameters should be chosen so that they disallow an adversary to be +certain about the origin of any response messages while keeping efficiency in +mind, i.e., the chosen approach should aim to maximize the adversarial +uncertainty gained per millisecond added delay. In practice this could mean to +start a limited random walk on the graph and for each traversed hop add a +plausible per-hop delay sampled from a suitable random latency distribution +(e.g., log-normal). In aggregate, this would create a plausible extended path +similar to the 'shadow route extension' as discussed in [BOLT +#7](07-routing-gossip.md#recommendations-for-routing). + ### Committing Updates So Far: `commitment_signed` When a node has changes for the remote commitment, it can apply them, diff --git a/04-onion-routing.md b/04-onion-routing.md index d61542c6f..cd53a155e 100644 --- a/04-onion-routing.md +++ b/04-onion-routing.md @@ -1446,7 +1446,7 @@ The _origin node_: - MUST NOT expose the `channel_update` to third-parties in any other context, including applying the `channel_update` to the local network graph, send the `channel_update` to peers as gossip, etc. - - SHOULD then retry routing and sending the payment. + - SHOULD then retry routing and sending the payment over a different path. - MAY use the data specified in the various failure types for debugging purposes. diff --git a/07-routing-gossip.md b/07-routing-gossip.md index e306b6788..0c518f31b 100644 --- a/07-routing-gossip.md +++ b/07-routing-gossip.md @@ -1017,6 +1017,11 @@ This effectively creates a _shadow route extension_ to the actual route and provides better protection against this attack vector than simply picking a random offset would. +Similarly, senders that consider the historical payment latency over candidate +hops as input for their routing algorithm should exclude the final hop from +such scoring, to account for the receiver-induced delay (see [BOLT +#2](02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc)). + Other more advanced considerations involve diversification of route selection, to avoid single points of failure and detection, and balancing of local channels. diff --git a/12-offer-encoding.md b/12-offer-encoding.md index db920f5a1..866241bca 100644 --- a/12-offer-encoding.md +++ b/12-offer-encoding.md @@ -529,6 +529,7 @@ The reader: - otherwise (no `offer_amount`): - MUST reject the invoice request if it does not contain `invreq_amount`. - SHOULD send an invoice in response using the `onionmsg_tlv` `reply_path`. + - SHOULD add a random delay before sending the invoice. - otherwise (no `offer_issuer_id` or `offer_paths`, not a response to our offer): - MUST reject the invoice request if any of the following are present: - `offer_chains`, `offer_features` or `offer_quantity_max`. @@ -714,6 +715,7 @@ A writer of an invoice: `invreq_chain`. - if the invoice is in response to an `invoice_request`: - MUST copy all non-signature fields from the invoice request (including unknown fields). + - SHOULD add a random delay before sending the invoice. - if `invreq_amount` is present: - MUST set `invoice_amount` to `invreq_amount` - otherwise: @@ -847,6 +849,11 @@ a response to an invoice request, that field must have existed due to the invoice request requirements, and we also require it to be mirrored here. +As the sender of an invoice request might attempt to utilize the time +difference between sending the `invreq` and receiving the corresponding +`invoice` or `invoice_error` response to draw conclusions on the identity of +the receiver (i.e., writer of the response), the latter should wait for a +random amount of time before responding to an `invreq` message. # Invoice Errors @@ -880,6 +887,7 @@ A writer of an invoice_error: - MUST set `suggested_value` to a valid field for that `tlv_fieldnum`. - otherwise: - MUST NOT set `suggested_value`. + - SHOULD add a random delay before sending the `invoice_error`. A reader of an invoice_error: FIXME!