Skip to content
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

Drop ReceivedMessage and handle sending decoys in handshake #66

Merged
merged 3 commits into from
Sep 30, 2024

Conversation

nyonson
Copy link
Collaborator

@nyonson nyonson commented Sep 25, 2024

Drop ReceivedMessage

  • Dropping the ReceivedMessage struct in favor of the PacketType enum and Payload struct.
  • The heart of the refactor is in PacketReader::decrypt_contents, everything kinda bubbles up from there. That is still the spot where I am not quite sure to do with the header byte (which is currently only used to flag decoy packets). The caller probably doesn't care about the header byte, but it is difficult to ask for memory allocation to include it, but then ignore it. Figure most will use the with_alloc version though where we wrap it behind the Payload struct, so keeping it simple here for now.
  • The PacketHandler functions where greatly simplified after this refactor, so went ahead and just dropped the wrapper functions and made the underlying reader/writers public.

Send Decoy Packets

Extend the complete_materials step of the handshake to optionally send decoy packets. This brings the library 100% up to spec, but more importantly for now, allows for an easy nice unit tests which covers both parties tossing garbage and decoys into the handshake.

Small Library Tweaks

  • Removed Debug derivations on structs which hold secret values, best practice for security.
  • Standardized error display punctuation.
  • Renamed the MessageLengthTooSmall error variant to CiphertextTooSmall for clarity.
  • Dropped un-used error variants to simplify API.
  • Standardized use of NUM_* prefix in consts which are specifying the number of bytes and not the bytes themselves.
  • Lint'd some assert usage in the tests.

Proxy Updates

  • Handle decoy packets, they are simply ignored on the V2 side.

Documentation

  • Consistent usage of "packet", "contents", and "message". Based it on the BIP324 spec. Added a blurb at the top of the module to help document this since we never use a struct to define the whole thing.
  • Standardized bullet point usage with * instead of -.

@nyonson nyonson changed the title Refactor ReceivedMessage interface Refactor ReceivedMessage and documentation Sep 25, 2024
@nyonson nyonson marked this pull request as ready for review September 25, 2024 20:00
@nyonson nyonson force-pushed the error-names-and-docs branch from cfde203 to 31f6e6a Compare September 26, 2024 17:03
@nyonson nyonson changed the title Refactor ReceivedMessage and documentation Drop ReceivedMessage and handle sending decoys in handshake Sep 26, 2024
@nyonson nyonson force-pushed the error-names-and-docs branch from bb3f073 to 6c4c59c Compare September 26, 2024 19:07
@nyonson nyonson force-pushed the error-names-and-docs branch from 6c4c59c to 1b40672 Compare September 26, 2024 19:10
protocol/src/lib.rs Outdated Show resolved Hide resolved
PacketType::Decoy => Ok(None),
PacketType::Genuine => {
// Drop the header byte.
contents.remove(0);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Because this is always the first element, each subsequent element will be shifted to the left on the stack. See this. I don't think this is worth the performance hit if we can help it

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah good catch. Removing front elements is such a pain...lot of tradeoffs here and not sure I have thought of something good yet.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think VecDeque has an additional byte of overhead but would allow pop_front in constant time. Either that or we just give the caller the decoy byte back and let them take a slice [1..]

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

VecDeque would definitely help the impl, but then returning that is weird for the caller. I am trying to find some uses of it in the ecosystem and am struggling.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Few ideas I am kicking around, trying to find the right balance between performance and complexity on the caller. And just to recap, the issue here is the header byte is covered by the auth tag so needs to present in the lower level libs, but is pretty useless for higher level callers.

  1. Took a look at the bytes crate just for some inspiration since I don't think we would want to add a new dependency. But didn't see anything revolutionary.
  2. Use a VecDeque instead of a Vec for the performance, but requires returning a VecDeque (or otherwise cancel out performance gains). I don't think these are used very often, for example can't find a single use in rust-bitcoin. Feels like a strange requirement to place on the caller given the hope is to lower confusion by removing the header byte.
  3. Anything involving Vec (e.g. drain) will at some point require some byte coping, no way around it. Could just leave it for now, but does feel pretty bad.

Does this lead us back to a custom type? Maybe one which owns the underlying vector but supplies a contents slice to the caller so they don't have to remember what the header byte is?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Preferably I would like to address the copies now because it will be a significant pain point for large messages like Block. I agree that the VecDeque is not a good return value because iterating over a message backwards is meaningless to the caller. I can't exactly envision how the custom type would resolve the problem. You can fork this and try a new patch or just write over this one if you think you can resolve it that way

@nyonson nyonson force-pushed the error-names-and-docs branch 2 times, most recently from 69069c7 to 981479d Compare September 27, 2024 21:08
@nyonson nyonson force-pushed the error-names-and-docs branch from 981479d to ed6e361 Compare September 27, 2024 21:16
@rustaceanrob
Copy link
Collaborator

utACK ed6e361

@rustaceanrob
Copy link
Collaborator

Did you happen to test a handshake against a regtest instance?

Self { bytes }
}

/// Contents of the payload.
Copy link
Collaborator

@rustaceanrob rustaceanrob Sep 28, 2024

Choose a reason for hiding this comment

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

Might want to add something like "excluding the ignore bit" for clarity. Not important at the moment though, just before next release

@nyonson
Copy link
Collaborator Author

nyonson commented Sep 30, 2024

Did you happen to test a handshake against a regtest instance?

Gave that a shot now. I had to add the --ignored flag to the regtest.sh script to make the regtest_handshake.sh run. The test passes, but the stop command is error'ing out for some reason. I'll take a look at that in a separate PR.

@nyonson nyonson merged commit cd584df into rust-bitcoin:main Sep 30, 2024
7 checks passed
Sign up for free to 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.

ReceivedMessage isn't quite right
2 participants