Refactoring to support future methods#406
Refactoring to support future methods#406ElsaLopez133 wants to merge 13 commits intolake-rs:mainfrom
Conversation
7204516 to
af4dbe6
Compare
af4dbe6 to
97097f9
Compare
For each function we match on state and create method-specific fiunctions. For example, we have r_prepare_message_2 and we match based on emthod to either use t_prepare_message_2_statstat or r_prepare_message_2_psk
9976f2b to
f54f4df
Compare
f54f4df to
69792a9
Compare
| #[derive(Debug)] | ||
| pub enum ProcessingM2 { | ||
| StatStat(ProcessingM2StatStat), // PSK(PProcessingM2PSK) // To be added later | ||
| } | ||
| #[derive(Debug)] | ||
| #[repr(C)] | ||
| pub struct ProcessingM2 { | ||
| pub struct ProcessingM2StatStat { | ||
| pub mac_2: BytesMac2, | ||
| pub prk_2e: BytesHashLen, | ||
| pub th_2: BytesHashLen, | ||
| pub x: BytesP256ElemLen, | ||
| pub g_y: BytesP256ElemLen, | ||
| pub plaintext_2: BufferPlaintext2, | ||
| pub c_r: ConnId, | ||
| pub id_cred_r: IdCred, | ||
| pub ead_2: EadItems, | ||
| } |
There was a problem hiding this comment.
This makes all the state of ProcessingM2 & co dependent on the method, rather than (as in the last call) just the parts that differ in other methods. Which of those fields are actually different in PSK?
I'd have expected something more like
#[derive(Debug)]
pub struct ProcessingM2 {
pub method_specifics: ProcessingM2MethodSpecifics,
pub prk_2e: BytesHashLen,
pub th_2: BytesHashLen,
pub x: BytesP256ElemLen,
pub g_y: BytesP256ElemLen,
pub plaintext_2: BufferPlaintext2,
pub c_r: ConnId,
pub ead_2: EadItems,
}
pub enum ProcessingM2MethodSpecifics {
StatStat {
pub mac_2: BytesMac2,
pub id_cred_r: IdCred,
},
// PSK, -- is empty, but in other stages it might have fields that StatStat has not.
}so that the 90% of the code that would be duplicated can still reach for the common items.
a18f9ce to
a5de4f7
Compare
We avoid repetition of shared-values among methods This affects ProcessingM2 and ProcessingM3
a5de4f7 to
35820e5
Compare
Adding enum in prepare_message_2 to define inputs based on method
bc90672 to
dd223be
Compare
- Made static keys I and R method dependednt (not needed ofr PSK) - Added high level identity enums - Made i_verify_message_2 take optional I - Added ProcessedM2MethodSpecifics and ParsedMessage2Detials - Updated i_parse_message_2 and high level initiaotr API - Adapted lakers-python and lakers-c
dd223be to
ee44c6e
Compare
7dc5c68 to
46e2ecc
Compare
chrysn
left a comment
There was a problem hiding this comment.
(I'm a bit sloppy in the review a bit on the C side, treating that as "if the test pass it will be fine", but I don't treat that as a high-priority feature.)
Doing the changes (including back-and-forth on how much is in the structs) and file-to-file moves makes this rather hard to review. Nothing sensible to be done here though -- these kinds of refactor are known to be hard, and there are no good generic solutions. (Moving things into different files only after all other changes are understood to be good would have helped, but that's hard to roll back again w/o starting over).
Not for other reviewers: --ignore-all-space is your friend.
| pub plaintext_2: BufferPlaintext2, | ||
| pub c_r: ConnId, | ||
| pub id_cred_r: IdCred, | ||
| pub ead_2: EadItems, |
There was a problem hiding this comment.
Most of these are actually method independent (ead_2 and c_r for sure, probably also th_2 and g_y) – AIU this does get changed back later in the same PR.
| pub ead_3: EadItems, | ||
| } | ||
|
|
||
| #[derive(Debug)] |
There was a problem hiding this comment.
This was a dead code struct, right? (No need to split it out, let's just confirm this so that if we wonder, we'll find our considerations.)
There was a problem hiding this comment.
yes, no longer there
lib/src/edhoc.rs
Outdated
| ProcessingM3::StatStat(inner) => r_verify_message_3_statstat(inner, crypto, valid_cred_i), // ProcessingM3::Psk(inner) => r_verify_message_3_psk(inner, crypto, valid_cred_i), | ||
| } | ||
| } | ||
| pub fn r_verify_message_3_statstat( |
There was a problem hiding this comment.
This shouldn't need to be pub. (Or if so, document why.).
There was a problem hiding this comment.
they are pub because now they are inside edhoc/statstat.rs, otherwise they are not accessible. Changed to pub(crate)
lib/src/edhoc.rs
Outdated
| } | ||
| } | ||
|
|
||
| pub fn r_prepare_message_2_statstat( |
lib/src/edhoc.rs
Outdated
| _ => Err(EDHOCError::UnsupportedMethod), | ||
| } | ||
| } | ||
| pub fn r_parse_message_3_statstat( |
lib/src/edhoc.rs
Outdated
| _ => Err(EDHOCError::UnsupportedMethod), | ||
| } | ||
| } | ||
| // returns c_r |
There was a problem hiding this comment.
Is this comment even still accurate? (And if so, it'll still belong to i_parse_message_2, and should be a more specific doc comment)
There was a problem hiding this comment.
old comment, will remove
lib/src/edhoc/statstat.rs
Outdated
| @@ -94,36 +97,44 @@ pub fn r_parse_message_3_statstat( | |||
| } | |||
|
|
|||
| pub fn r_verify_message_3_statstat( | |||
There was a problem hiding this comment.
Now this is not statstat specific any more, as it does the switching internally just again.
(And r_verify_message_3 just forwards into here)
There was a problem hiding this comment.
True, I can directly pass the arguments in the r_verify_message_3 and do the match in the outer function, rather than doing it twice!
| } | ||
| // EDHOCMethod::PSK => r_prepare_message_2_psk() | ||
| // (EDHOCMethod::PSK, PrepareMessage2Details::Psk) => | ||
| _ => Err(EDHOCError::UnsupportedMethod), |
There was a problem hiding this comment.
That is not necessarily the error here: The error is "the details you provided do not match what we agreed on with the peer". This should at least be a comment here until we find a good plan.
lib/src/lib.rs
Outdated
| r: BytesP256ElemLen, // private authentication key of R | ||
| cred_r: Credential, // R's full credential | ||
| state: ResponderStart, // opaque state | ||
| r: Option<BytesP256ElemLen>, // private authentication key of R when required by method |
There was a problem hiding this comment.
Why is this deviating from the method-enum path?
There was a problem hiding this comment.
Before message_1, the Responder does not yet know the selected EDHOC method, so it must carry identity material. For StatStat, that includes the private r key.
You’re right that using Option plus an identity enum is redundant (I did have the RepsonderIdentity enum). I’ll switch to carrying ResponderIdentity directly and derive method-specific details at prepare_message_2 (once state.method is known), which removes the extra Option adn keeps the enum style.
shared/src/lib.rs
Outdated
|
|
||
| #[derive(Debug)] | ||
| pub enum ParsedMessage2Details { | ||
| StatStat { id_cred_r: IdCred, ead_2: EadItems }, |
There was a problem hiding this comment.
EAD items will be in any message 2 details. (No need for a struct I think: they can be returned side by side in the multi-value return that returns PasedMessage2Details).
d218a10 to
0af8c8b
Compare
1. Remove old comments (returns c_r) 2. Made r_verify_message_3 method distinction in the outer level (so r_verify_message_3_statstat does not do repeated matches) 3. Add a FIXMEE on the error type. 4. Modified r: Option<> to be method-enum, matching the current sytle and avoiding repetition (ResponderIdentity is the enum) 5. ParsedMessage2Detials: removed ead_2 6. Changed pub to pub(crate) in statstat.rs
0af8c8b to
c63cd51
Compare
WilliamTakeshi
left a comment
There was a problem hiding this comment.
Heyyy, I really like how the code is shaping up. Just wrote some ocmments, the ones that are nitpick, feel free to skip them :))
| pub kind: ProcessingM2MethodSpecificsKindC, | ||
| pub mac_2: BytesMac2, | ||
| pub id_cred_r: IdCred, | ||
| } |
There was a problem hiding this comment.
I think here its supposed to be
#[derive(Debug)]
#[repr(C)]
pub enum ProcessingM2MethodSpecificsKindC {
Pm2StatStat {
pub mac_2: BytesMac2,
pub id_cred_r: IdCred,
},
}
because mac2 and id_cred_r will only exists for the StatStat, right?
If not, then mac_2 and id_cred_r shouldn't be inside the method_specifics field.
maybe its different because is the C version? I dont know
There was a problem hiding this comment.
Yes, I am not sure how to do it in C. The problem is that in C there is no tagged enum with payload, as in Rust. Check commit 3e405f8 where i am trying to replicate it using the union + kind.
1. Follow the same pattern for InitiatorIdentity (similar to RepsonderIdentity) instead of making i: Option<> 2. Fix in lakers-python/src/repsonder.rs: minimize the use of ? by extracting the value only once 3. Avoid wildcard imports 4. Add FIXME for the error type. Need to find a good one 5. Removing unnecesary method in ProcessedM2
57596ab to
c93fffd
Compare
Using struct+union to replicate the enum style in Rust
| method_specifics: ProcessedM2MethodSpecificsC { | ||
| kind: ProcessedM2MethodSpecificsKindC::Prm2StatStat, | ||
| data: ProcessedM2MethodSpecificsDataC { | ||
| statstat: core::mem::ManuallyDrop::new(ProcessedM2StatStatC {}), |
There was a problem hiding this comment.
I only see ManuallyDrop::new, but no ManuallyDrop::drop. As far as I know, when using ManuallyDrop, the inner value must eventually be dropped manually (e.g., with ManuallyDrop::drop or ptr::drop_in_place); otherwise, it will leak.
There was a problem hiding this comment.
In this specific case, ProcessedM2StatStatC {} is an empty type with no destructor, so there is nothing to drop and no leak from that field. The reason why ManuallyDrop is used is that it's the safe way to put fields in a union, especially for future non-trivial payloads, as in PSK.
There was a problem hiding this comment.
I am still not sure about using ManuallyDrop. In this case its fine because is a zero-sized field, but on the PSK will have to manually drop it, right?
I think the right path is to have something that derives Copy. @chrysn can you check this and these new changes? It would be great to have this (and the other one) merged soon.
There was a problem hiding this comment.
I think that if we want to have Copy then we need CredentialC to also implement Copy.
We could also avoid using the union, but I am not sure how to do the enum-style in C otherwise
WilliamTakeshi
left a comment
There was a problem hiding this comment.
I didn't take a look on the C code much, because I know there is some discussion if we pause the C bindings for now.
- Adding a SAFETY comment in lakers-c/src/lib - Adding a FIXME to define a new error type (method_specifics doesnt match with the what was agreed) - Correcting prk_4e3m and prk_3e2m to avoid matching on symmetric credential in statstat (since now it is only the stat) - Remove _ead_2, since it is used
chrysn
left a comment
There was a problem hiding this comment.
We're converging in many areas, but I still think that the bulk move into edhoc/statstat.rs is excessive, especially seeing that it just leads to duplication later in #415.
Minimizing that duplication is not just something we should aim for because we strive for code quality, but because given that we're the first and AFAIK so far only implementation that has a method >3, will also help LAKE people become better at understanding what typical things that a method customizes are. We won't set those in stone, but our code is also a visual guideline for method developers for what methods such as 4 have changed so far.
Before you go on an editing spree, can we discuss (also possibly in chat or a video call, not sure yet when I'll be around) what good paths forward without too much disruption are? One option I'd consider is to acknowledge that a split-out refactoring step has served its purpose well, we've hashed out a lot in here, but in the interest of not making your processing needlessly complex (undoing some of the move-into-statstat would be hell of a rebase) we can continue on #415 (once we're sure not to lose anything from in here), refactor things back into a less duplicated state there, and then continue working on that view of the change as a whole.
| r_prepare_message_2_statstat(state, crypto, cred_r, r, c_r, cred_transfer, ead_2) | ||
| } | ||
| // (EDHOCMethod::PSK, PrepareMessage2Details::Psk) => | ||
| // FIXME: it is not an error, but more a lack of agreement between peers. |
There was a problem hiding this comment.
Continuing from https://github.com/lake-rs/lakers/pull/406/changes#r2888495250 so I can change the text here:
| // FIXME: it is not an error, but more a lack of agreement between peers. | |
| // FIXME: it is not a runtime error, but a programming error: The library user has seen | |
| // StatStat details in message 1 and still provided other details creating message 2. |
| #[derive(Debug)] | ||
| pub enum InitiatorIdentity { | ||
| StatStat { i: BytesP256ElemLen }, | ||
| Psk, |
| #[derive(Debug)] | ||
| pub enum ResponderIdentity { | ||
| StatStat { r: BytesP256ElemLen }, | ||
| Psk, |
| ProcessingM1, ProcessingM2, ProcessingM2MethodSpecifics, ProcessingM3, | ||
| ProcessingM3MethodSpecifics, WaitM2, WaitM3, WaitM3MethodSpecifics, WaitM4, | ||
| }; | ||
| use lakers_shared::Crypto as CryptoTrait; |
There was a problem hiding this comment.
The functions in here IMO still do way more than they should, as evidenced by a diff between lib/src/edhoc/psk.rs and lib/src/edhoc/statstat.rs the in #415:
Those easily share 20 lines in a row in many of the functions, typically at the start and end. (Sometimes that's just masked by different choices of early return and thus indentation, eg. starting from compute prk_out in r_verify_message_3_*).
Refactoring current code to add additional methods in the future (PSK)
methodin some states to be able to match on it.r_verify_message_3_statstat,i_verify_message_2_statsat)