-
Notifications
You must be signed in to change notification settings - Fork 77
feat: add SHA-256 and SHA-512 wrapper implementations #692
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
Conversation
1336912 to
4273d74
Compare
adr1anh
left a comment
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.
Looks great and thanks for taking this on. Not a full review, but I wonder if we could consolidate some code to be shared between SHA256/512 or even with other binary hash functions.
| } | ||
|
|
||
| /// Cast the slice into contiguous bytes. | ||
| fn prepare_merge<const N: usize, D>(args: &[D; N]) -> &[u8] |
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 feels like a more generally useful function that we might want to make available/reuse across different modules. Was this copied from another hash function wrapper?
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.
Yes, this was copied from the blake and keccak modules which have identical implementations.
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.
Can we share them instead of duplicating them?
Al-Kindi-0
left a comment
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.
Look good, thank you!
|
Hi @huitseeker, I received email notifications about your review comments In the meantime, I've addressed what I understood from the emails but did not push yet:
|
miden-crypto/src/hash/sha2/mod.rs
Outdated
|
|
||
| impl Digest for Sha512Digest { | ||
| fn as_bytes(&self) -> [u8; 32] { | ||
| // Return first 32 bytes of the 64-byte digest |
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 truncates SHA-512 to 32 bytes. That gives different output than the NIST SHA-512/256 standard.
For input "abc":
- Truncated SHA-512 (this code): ddaf35a1...d55d39a
- SHA-512/256 (NIST standard): 53048e26...07e7af23
SHA-512/256 uses different starting values, so truncating gives the wrong answer.
Please add a test showing what this actually does. Use a FIPS 140-3 test vector so it's clear this is truncated SHA-512, not SHA-512/256. Also add a comment on line 265 explaining the truncation.
If you need real SHA-512/256, the sha2 crate has Sha512_256.
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.
Done in ae7bc92
huitseeker
left a comment
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.
@Farukest Yep, I was super unhappy with the tool that helps me add context to PR comments from my notes. So I deleted the comments, and they are now in a better shape.
The main item is being spectacularly clear in what we're doing with truncated SHA2 variants, which are not the ones that are specified in FPS-140 (those specified variants are using different IVs).
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.
Actually, so sorry for the back and forth @Farukest but we won't be exposing truncated SHA512/256t, aka the truncated SHA-512 with the non-standard IVs, because it has zero usage footprint. We'd like to expose SHA-512/256 instead, which requires using the proper IVs. It's exposed in the sha2 crate as Sha512_256. Could you help make this change?
Edit: never mind, trying to figure out how to do something that makes sense here.
Ah, that makes no sense in the current shape of the PR. Never mind
huitseeker
left a comment
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 probably do not want to implement Digest for Sha512 for this PR. In the current shape of the trait because it forces the as_bytes function to have a 32 byte output while you're trying to expose a 64 byte hasher.
The appropriate output for the SHA-512 hasher is a 64 byte output and this forces you to use SHA-512 truncated to 256 bits with the "wrong" IVs. This is a function that has almost no usage.
What we would like to do instead is extend the Digest trait in winterfell so that it takes a const generic parameter, but providing a default for that const generic parameter to the value of 32, which will make all instances already using Digest implicitly mean Digest<32>.
In turn, this will modify the output of the as_bytes function so that the return type takes an array of bytes of a length depending on the const generic. This should let you implement Digest<64> for SHA-512. What do you think of this solution?
That sounds good to me @huitseeker . Then; I'll remove the |
|
@Farukest That sounds great. The cherry on top is if you could use my comment to open an issue on Winterfell, and refer to it in a line of code comment on SHA-512 in this PR explaining why we're not implementing |
|
I opened on winterfell @huitseeker and have one question that confuses my mind now. The Hasher trait requires type |
I would remove the trait implementations and keep the standalone methods. The traits are there for hash functions that we use for STARK proof generation, and SHA512 is not one of these hash functions (at least not in the near future) - so, we don't have to implement these traits for it. |
Implements Hasher, HasherExt, and ElementHasher traits for SHA2 hash functions. Includes NIST test vectors and property-based tests. Closes 0xMiden#689
- Add #[repr(transparent)] to Sha256Digest and Sha512Digest for safe pointer casting in digests_as_bytes() - Document that Sha512Digest::as_bytes() returns truncated SHA-512, NOT SHA-512/256 (different IVs per FIPS 180-4) - Add memory layout tests to verify struct size and alignment assumptions - Add digests_as_bytes correctness tests for both digest types - Add PropTest for merge_many to verify unsafe code produces correct results - Add test demonstrating SHA-512 truncation vs SHA-512/256 difference
04224c8 to
a97285a
Compare
Done @bobbinth |
SHA-512 produces 64-byte output which is incompatible with Winterfell's Digest trait (requires 32-byte as_bytes()). Standalone methods are kept. See facebook/winterfell#406
a97285a to
47fd139
Compare
huitseeker
left a comment
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 looks great, thank you so much @Farukest !
Describe your changes
Implements Hasher, HasherExt, and ElementHasher traits for SHA2 hash functions.
Closes #689
Checklist before requesting a review