-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Onion messages v1 #1503
Onion messages v1 #1503
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1503 +/- ##
==========================================
- Coverage 91.03% 90.95% -0.08%
==========================================
Files 80 85 +5
Lines 44194 44679 +485
Branches 44194 44679 +485
==========================================
+ Hits 40233 40639 +406
- Misses 3961 4040 +79
Continue to review full report at Codecov.
|
According to @t-bast (and my experience), the spec test vectors are all broken and won't be fixed until lightning/bolts#765 has ACKs on the data model. Still gonna write our own tests, but removed the spec test vectors from the PR TODOs so they aren't blocking. |
eaecccd
to
050268a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Browsed the new onion_message.rs
API. Catching up with the spec itself.
lightning/src/ln/onion_message.rs
Outdated
pub fn new<Signer: Sign, K: Deref>(node_pks: Vec<PublicKey>, keys_manager: K) -> Result<Self, ()> | ||
where K::Target: KeysInterface<Signer = Signer>, | ||
{ | ||
if node_pks.len() <= 1 { return Err(()) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would we like to enforce a max length ? From my understanding the specs isn't recommending one. I think we may be interested to check one at blinded route reception for memory bounds reasons, as it's a third-party input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a TODO to ensure that outbound onion packets can't exceed BIG_PACKET_HOP_DATA_LEN
. Reasoning is that Eclair will drop onion messages that exceed this length
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's a value shared among implementation, nice to add it to the spec imo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, forgot to mention but as you mentioned below it's in the spec: https://github.com/lightning/bolts/pull/759/files#diff-ad65f0beaac5cef88f5fd7a8b9ca36cbc5a790f4815b4b50b9ea794a55aaf012R1421
lightning/src/ln/onion_message.rs
Outdated
/// If `path_id` is `Some`, it is used to identify the blinded route that this onion message is | ||
/// sending to. This is useful for receivers to check that said blinded route is being used in | ||
/// the right context. | ||
path_id: Option<[u8; 32]> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion : if path_id
usage is to identify that an encrypted_payload is arriving from the expected, last-hop node id, we should call it something like blinded_route_id
to avoid confusion with the notion of a payment path.
A part of that, it's unclear to me what kind of further checks could be realized to verify the "right context usage". I would be concerned it could introduce "naive" deanonymization attacks, where the encrypted path_id
is tampered with to observe success/errors from timing processing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing. Thankfully, the path_id
cannot be tampered with -- it's always provided by the receiver in an encrypted and HMAC-d blob
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right after reading the spec, if it's tampered it should break at the HMAC-level.
lightning/src/ln/onion_message.rs
Outdated
let node_secret = match self.keys_manager.get_node_secret(Recipient::Node) { | ||
Ok(secret) => secret, | ||
Err(e) => { | ||
log_trace!(self.logger, "Failed to retrieve node secret: {:?}", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "Onion Reception : Failed to retrieve node secret" ? get_node_secret
is used few times across the codebase, nice to provide more info to identify the callsite.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This log should be prefixed by the onion_messages
module name, do you think that helps? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say yes, we start to have a lot of logs, being able to observe specific subsystem help to debug test from exp.
050268a
to
3d7d7ad
Compare
To get the next hop's packet's pubkey. This will be used to DRY onion message forwarding in the upcoming Onion Messages PR lightningdevkit#1503
To get the next hop's packet's pubkey. This will be used to DRY onion message forwarding in the upcoming Onion Messages PR lightningdevkit#1503
3d7d7ad
to
d2ef7c5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really quick initial first pass, but generally I think this is looking pretty good. The API seems sensible and the implementation is pretty straightforward.
lightning/src/ln/onion_message.rs
Outdated
Receive { | ||
/// If `path_id` is `Some`, it is used to identify the blinded route that this onion message is | ||
/// sending to. This is useful for receivers to check that said blinded route is being used in | ||
/// the right context. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need a TODO
to make it non-optional? Or are there reasons to set it to None
once we're done with our full implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be None
in the future if someone were sending to our unblinded public key and not to a blinded route we create
lightning/src/ln/onion_message.rs
Outdated
} | ||
|
||
impl Writeable for Packet { | ||
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is Packet
never written/read in tests? At least according to codecov.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's bizarre, is there a link to that? Can't find it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
codecov may be wrong, but https://app.codecov.io/gh/lightningdevkit/rust-lightning/compare/1503/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr%20comments&utm_term=lightningdevkit#D8L53 you may have to click to open up the onion_message.rs diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, when I add logs to the read/write methods in the tests they def get hit 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh codecov sucks.
d2ef7c5
to
d40751f
Compare
d40751f
to
9223986
Compare
9223986
to
fb10b10
Compare
Will add two missing tests next but pushed up the latest changes, main difference being somewhat extensive module-level documentation being added and the new sending errors. |
0dfad2a
to
15983c2
Compare
This is good for review! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed so far until 15983c2
lightning/src/onion_message.rs
Outdated
/// Control TLVs for the final recipient of an onion message. | ||
Receive { | ||
/// If `path_id` is `Some`, it is used to identify the blinded route that this onion message is | ||
/// sending to. This is useful for receivers to check that said blinded route is being used in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: As I understand the path_id
is useful for the receiver, so it could say "this onion message is coming from".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, in my mental model you send an onion message to a blinded route, which aligns with it being a Destination
variant.
lightning/src/ln/onion_message.rs
Outdated
pub fn new<Signer: Sign, K: Deref>(node_pks: Vec<PublicKey>, keys_manager: K) -> Result<Self, ()> | ||
where K::Target: KeysInterface<Signer = Signer>, | ||
{ | ||
if node_pks.len() <= 1 { return Err(()) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's a value shared among implementation, nice to add it to the spec imo.
lightning/src/ln/onion_message.rs
Outdated
/// If `path_id` is `Some`, it is used to identify the blinded route that this onion message is | ||
/// sending to. This is useful for receivers to check that said blinded route is being used in | ||
/// the right context. | ||
path_id: Option<[u8; 32]> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right after reading the spec, if it's tampered it should break at the HMAC-level.
lightning/src/ln/onion_message.rs
Outdated
let node_secret = match self.keys_manager.get_node_secret(Recipient::Node) { | ||
Ok(secret) => secret, | ||
Err(e) => { | ||
log_trace!(self.logger, "Failed to retrieve node secret: {:?}", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say yes, we start to have a lot of logs, being able to observe specific subsystem help to debug test from exp.
282ed9e
to
a063de6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review ACK e4a50a3
Changes since last review:
- minor comments change around
construct_onion_packet_with_init_noise
- buffered read for
Packet
- clarification of
ecdh()
comment - new
construct_onion_message_packet
to initializeChaCha20
- restructuring of
packet_payloads_and_keys
- spec rational comment in
construct_onion_message_packet
- new
SendError::TooFewBlindedHops
and corresponding test
Blinded routes can be provided as destinations for onion messages, when the recipient prefers to remain anonymous. We also add supporting utilities for constructing blinded path keys, and control TLVs structs representing blinded payloads prior to being encoded/encrypted. These utilities and struct will be re-used in upcoming commits for sending and receiving/forwarding onion messages. Finally, add utilities for reading the padding from an onion message's encrypted TLVs without an intermediate Vec.
e4a50a3
to
3d6e0a8
Compare
3d6e0a8
to
cb7bb84
Compare
}; | ||
|
||
let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap(); | ||
let pending_msgs = pending_per_peer_msgs.entry(next_node_id).or_insert(Vec::new()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to keep track of if we're actually connected to the given peer here, and simply drop the message if we're not. We can do this in the followup that wires this up to PeerManager, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, added a TODO on the follow-up PR to address soon
} | ||
} | ||
|
||
pub(crate) fn decode_next_hop<D: DecodeInput, R: ReadableArgs<D::Arg>, N: NextPacketBytes>(shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32], decode_input: D) -> Result<(R, Option<([u8; 32], N)>), OnionDecodeErr> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really not a fan of this being public with all the trait bounds that get auto-implemented based on what's passed in. Can we make this private and add a decode_next_message_hop
like we have for decode_next_payment_hop
, then we can make the DecodeInput
and NextPacketBytes
traits priv? Happy to see this in a followup, too, if you're feeling lazy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Noted in the follow-up issue, will aim to be a quick follow-up
cb7bb84
to
4919172
Compare
LGTM, feel free to squash when other reviewers are happy. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM modulo one comment. Feel free to squash.
…noise for it We need to add a new Packet struct because onion message packet hop_data fields can be of variable length, whereas regular payment packets are always 1366 bytes. Co-authored-by: Valentine Wallace <vwallace@protonmail.com> Co-authored-by: Jeffrey Czyz <jkczyz@gmail.com>
This method will help us avoid retrieving our node secret, something we want to get rid of entirely. It will be used in upcoming commits when decoding the onion message packet, and in future PRs to help us get rid of KeysInterface::get_node_secret usages across the codebase
OnionMessenger will be hooked up to the PeerManager to send and receive OMs in a follow-up PR.
This adds several utilities in service of then adding OnionMessenger::send_onion_message, which can send to either an unblinded pubkey or a blinded route. Sending custom TLVs and sending an onion message containing a reply path are not yet supported. We also need to split the construct_keys_callback macro into two macros to avoid an unused assignment warning.
This required adapting `onion_utils::decode_next_hop` to work for both payments and onion messages. Currently we just print out the path_id of any onion messages we receive. In the future, these received onion messages will be redirected to their respective handlers: i.e. an invoice_request will go to an InvoiceHandler, custom onion messages will go to a custom handler, etc.
Pre-existing to this PR, we were reading next packet bytes with io::Read::read, which is not guaranteed to read all the bytes we need, only guaranteed to read *some* bytes. We fix this to be read_exact, which is guaranteed to read all the next hop packet bytes.
4919172
to
17ec697
Compare
Implement v1 of onion messages per lightning/bolts#759. This will enable us to implement Offers messaging.
TODOs
tests from BOLT 7: Onion message support (features 38/39) lightning/bolts#759:bolt04/enctlvs.json
bolt04/onion-route-blinding-test.json
bolt04/route-blinding-override-test.json
bolt04/route-blinding-test.json
hop_data
to exceedBIG_PACKET_HOP_DATA_LEN
(because eclair will refuse to forward these)Follow-ups documented in #1607
Based on #1518