Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Allow duplicate-payment_hash HTLCs for HTLC forwards - #167

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc
Sep 12, 2018
Merged

Allow duplicate-payment_hash HTLCs for HTLC forwards#167
TheBlueMatt merged 4 commits into
lightningdevkit:masterfrom
TheBlueMatt:2018-09-dup-htlc

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this.

This isnt as simplifying as I'd hoped, but still increases
compile-time checking, which is nice, and removes one of two
panic!()s.
Comment threadsrc/ln/channel.rs
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't a change but maybe a clearer comment on this one or AwaitingRemoteRevokeToAnnounce could be better, "which we need them to do before we apply its HTLC on our commitment tx" ? To signal that sending a HTLC in commitment_signed it's the same that applying it on our commitment tx, that we only do when we received remote revoke_and_ack

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not 100% sure what you're suggesting here, but as its not a change I'm open to a new PR to change it.

Comment threadsrc/ln/channelmanager.rs Outdated
/// We hold various information about HTLC relay in the HTLC objects in Channel itself:
///
/// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
/// Forward the HTLC with information it will give back to us when it does so, or if it should Fail

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*forward

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() }).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not give back error here ? we can do it with HTLCSource internally now, right ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't fail backwards until revoke_and_ack tells us it is safe to do so, receiving an update_fail_htlc/update_fail_malformed_htlc is really only an indication from the remote side that they intend to fail the HTLC, its really once they've revoked their previous state that we consider it done.

session_priv: SecretKey,
},
/// Used for channel rebalancing
CycledRoute {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find HTLCSource cleaner but os there edge cases that do we want to prevent with CycledRoute to us ? Not at first glance to me but still wandering..

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope not? We can't tell the difference between a payment that went around the network and came back through us (unless we are the source) and two payments that are independant and is just an attempt to deanonymize a payment.

@ariard

Copy link
Copy Markdown

utACK, have review the whole, nothing shocks me!

This is required by BOLT 2 to ensure that no attacker can simply
relay every public node a duplicate-payment_hash HTLC for each HTLC
it receives to deduce where an HTLC came from.
Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.
This further simplifies the payment transition state a bit, so
hopefully at least we got some readability out of all of this
@yuntai

Copy link
Copy Markdown
Contributor

Note that this makes the claim logic much less incentive-compatible
as we will not claim all available HTLCs with the same payment_hash
even if we know the preimage! This is OK because, most likely, any
attackers trying to map the network will use small-value payments
and, hopefully, we will move away from constant hashes across an
entire payment at some point in the near future.

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

@TheBlueMatt

Copy link
Copy Markdown
CollaboratorAuthor

Duplicate claims will only happen when the recipient of a payment doesn't care about her privacy (and is also greedy) and issue multiple claims, so no reason to protect her while sacrificing our incentive? (also to cost less to the attackers)

No, any intermediate node can create a duplicate payment, which we would then claim. eg if Alice pays Eve through Bob, Charlie and Dave, Bob may send a payment with the same hash through a number of nodes on the network, including Dave, and if Dave claims all pending HTLCs which have the same hash when Eve gives Dave the preimage, then Bob will learn that the payment Alice sent went through Dave, which they shouldn't be able to learn due to the onion encryption.

@yuntai

Copy link
Copy Markdown
Contributor

Thanks, very clear!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@TheBlueMatt@ariard@yuntai