From 30515fb16e29720d6bfe441aab6a6b5ca3d5d5b9 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 30 May 2025 13:50:42 +0200 Subject: [PATCH 1/6] Recommend receiver-side random delays before claiming/failing HTLCs Timing attacks on privacy potentially allow on-path adversaries to determine the destination of an observed payment. To this end, they might merely need to record the time difference between sending `update_add_htlc` and receiving the corresponding `update_{fulfill,fail,fail_malformed}_htlc` response to be able to guess their distance to the destination and potentially deanonymize the latter. To counteract this, different implementations previously implemented a variety of mitigation, most commonly adding some kind of (at times randomized) delays when *forwarding* HTLCs. However, here we propose to instead (or additionally, if the implementations prefer) add a receiver-side delay before claiming or failing HTLCs, which puts the receiver's privacy improvements in their own hands. Additionally, adding a randomized delay on the receiver's end makes it easier to argue about how much delay should be added to somewhat reliably increase the anonymity set, as previously multiple intermediate hops (or none) could potentially add forwarding delays, which made picking a reasonable per-hop median delay rather hard. --- 02-peer-protocol.md | 10 ++++++++++ 07-routing-gossip.md | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 205772803..35a25a199 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_fulfill_htlc`, `update_fail_malformed_htlc`. #### Rationale @@ -2439,6 +2441,14 @@ 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 HTLC 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 be chosen so that the response messages could have +plausibly originated from a node downstream in 1-2 hops distance from the +receiving node. + ### Committing Updates So Far: `commitment_signed` When a node has changes for the remote commitment, it can apply them, 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. From ab2cafa90ebd26636c7746756221be726a2b55cf Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Mon, 2 Jun 2025 15:25:49 +0200 Subject: [PATCH 2/6] f `s/update_fulfill_htlc/update_fail_htlc/` --- 02-peer-protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 35a25a199..88a49d034 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -2418,7 +2418,7 @@ A receiving node: 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_fulfill_htlc`, `update_fail_malformed_htlc`. + `update_fail_htlc`, `update_fail_malformed_htlc`. #### Rationale From 8e8752eb0dd3456b87a51ddfb3c421777c0c312f Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 6 Jun 2025 11:07:54 +0200 Subject: [PATCH 3/6] f Give more detailed guidance on how to build aggregate delay --- 02-peer-protocol.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 88a49d034..e009ba9f2 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -2442,12 +2442,18 @@ 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 HTLC with `update_fulfill_htlc` / `update_fail_malformed_htlc` / +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 be chosen so that the response messages could have -plausibly originated from a node downstream in 1-2 hops distance from the -receiving node. +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` From 3118edbfbc73116f0b2364b54b6481259c81ca74 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 30 May 2025 14:17:20 +0200 Subject: [PATCH 4/6] Recommend random delays before `invoice`/`invoice_error` response For similar reasons to the previous commit, we also add recommendations for inserting random delays to the BOLT12 flow to impair timing analysis capabilities. --- 12-offer-encoding.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/12-offer-encoding.md b/12-offer-encoding.md index db920f5a1..860035a19 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: @@ -880,6 +882,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! From 047da4f8dbdf3ff6d5f3e193e56cbdc5a3db6060 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 6 Jun 2025 13:17:46 +0200 Subject: [PATCH 5/6] f Add invreq response rationale --- 12-offer-encoding.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/12-offer-encoding.md b/12-offer-encoding.md index 860035a19..866241bca 100644 --- a/12-offer-encoding.md +++ b/12-offer-encoding.md @@ -849,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 From 9d2704589701d5fb6e49a361d6ecb2aeec4c6c82 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Tue, 10 Jun 2025 10:19:31 +0200 Subject: [PATCH 6/6] Specify that retries SHOULD be attempted over different path --- 04-onion-routing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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.