New feature: SerializableState#48
Conversation
|
For now, I have added the trait and impl'd it for SHA2. I'll pause here and give a chance for people to give feedback before I continue with doing the same for:
|
| // insert the version tag | ||
| let out: &mut [u8; 105] = add_lib_ver(&mut out_to_return).try_into().unwrap(); | ||
|
|
||
| // state.h: [u32; 8] |
There was a problem hiding this comment.
The internal state of SHA2. It is called H^i_j in FIPS 180-4, see sections 2.2 and 6.2.
| out[40..104].copy_from_slice(&self.x_buf); | ||
|
|
||
| // x_buf_off: usize | ||
| // in general, a usize should be serialized into a u64, but in this case, it can't ever be larger than 64 |
There was a problem hiding this comment.
However, usize can be u32 on 32-bit platforms.
There was a problem hiding this comment.
That's true, but I don't think it affects the comment, right? For example, serde encodes a usize into a u64 because that's the largest it can ever be on any supported architecture. I think. Encoding a u32 into a u64 is perfectly fine.
I'm not sure I understand the point of your comment.
There was a problem hiding this comment.
I should have expressed myself in sentences. It seems that you care about endianess with to_le_bytes(). If that's true, and you can move a state across endianness, you should also care about moving a state across 32/64 bit CPUs.
If you serialise the state on 32 bits, usize is 4 bytes, and deserialise on 64, you will have to read 8 bytes.
There was a problem hiding this comment.
Right. So I think that the answer here is to not let it serialize a usize per the local architecture; instead I should always pick a concrete size that will be the same regardless of architecture, right? I think we're on the same page?
In general, that would mean always encoding a usize as a u64 (which I believe is what serde does), but in this particular case, the sha2 x_buf is 64 bytes, therefore the x_buf_off can never be larger than 64, which actually fits in a u8 ... so in this case there's no need to use 8 bytes when 1 byte will do.
This makes sense, right? I'm not talking crazy?
There was a problem hiding this comment.
Right. So I think that the answer here is to not let it serialize a usize per the local architecture; instead I should always pick a concrete size that will be the same regardless of architecture, right? I think we're on the same page?
Exactly.
In general, that would mean always encoding a usize as a u64 (which I believe is what serde does), but in this particular case, the sha2 x_buf is 64 bytes, therefore the x_buf_off can never be larger than 64, which actually fits in a u8 ... so in this case there's no need to use 8 bytes when 1 byte will do.
Yes, that's true.
This makes sense, right? I'm not talking crazy?
No, that makes sense.
|
|
||
| impl<PARAMS: SHA2Params> SerializableState<108> for SHA256Internal<PARAMS> { | ||
| fn serialize_state(&self) -> [u8; 108] { | ||
| let mut out_to_return = [0u8; 108]; |
There was a problem hiding this comment.
Where 108 and other sizes coming from?
There was a problem hiding this comment.
I have replaced all the magic numbers with named pub const's to make it clearer.
|
It looks okay, it'll really help with SLH-DSA as storing intermediate state is almost a requirement to getting the algorithm to work in real time... two things, and you may have to pardon my rust if I've got this wrong. It looks like the version check is automatically rejecting anything older, shouldn't that be newer? Ideally you'd be compatible 1 or 2 versions older, newer might be a bit problematic as you might not know the format. Also, for what it's worth, the LLM suggested LIB_VERSION could be derived from env!("CARGO_PKG_VERSION") with the actual version been something taken from the core API crate. |
My idea was to have a framework to be able to carry multiple versions of the parser in case we ... I don't know ... add a boolean flag to one of the objects for some reason. I honestly hadn't thought about blocking future versions. That's a good idea!
I also did some research but didn't find anything useful. Let me give this a bit more poking. Thanks David! |
2386f22 to
54f93f6
Compare
|
I don't know why 2d0b7f3 got included in this PR. I also don't know how to remove it. Sorry. |
…r the impl for SHA2 and SHA3.
46df1d1 to
937d859
Compare
Closes #24
This was a feature requested by Simo to be able to pause an operation -- particularly in the middle of a
do_update()...do_update()...do_final()flow -- stick the serialized crypto operation into a cache, and then resume it later. This is an important feature for implementing TLS loadbalancers that want to be able to cache out the HKDF state and resume it from a different box when the next flight of TCP messages come in.The only "creative" thing I've added here is that all serialized states are prefixed with a 3-byte semantic version of the library and it's checked on load back in. The idea is that if we ever need to change the serialization of some object, then we can add a guard to refuse to load a serialized object from before the guard (or keep both versions of the deserializer and switch based on the version tag, or whatever ... #futureProofing).