-
Notifications
You must be signed in to change notification settings - Fork 265
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
Implemented Grostl #10
Conversation
…atrix to its own mod
pub type Grostl224 = GrostlSmall<U28>; | ||
pub type Grostl256 = GrostlSmall<U32>; | ||
pub type Grostl384 = GrostlSmall<U48>; | ||
pub type Grostl512 = GrostlSmall<U64>; |
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.
Oops. The fact that GrostlSmall
compiles with a size greater than U32
is a problem...
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.
Thank you for your work!
Unfortunately it seems that according to E0122 "trait bounds are not (yet) enforced in type definitions" and because of the bug I've missed it. (also you have typo in GrostlSmall
which got through because of that, you needed to use Cmp<U33>
)
So you'll need to write structs explicitly like this:
#[derive(Default)]
pub struct GrostlSmall<OutputSize>
where OutputSize: ArrayLength<u8> + Cmp<U33>,
Compare<OutputSize, U33>: Same<Less>
{
grostl: Grostl<OutputSize, U64>,
}
impl<OutputSize> Digest for GrostlSmall<OutputSize> {
type OutputSize = OutputSize;
type BlockSize = U64;
fn input(&mut self, input: &[u8]) {
self.grostl.process(input);
}
fn result(mut self) -> GenericArray<u8, Self::OutputSize> {
self.grostl.finalize()
}
}
It's probably not worth to implement Digest
for Grostl
in this situation.
I will review your code shortly.
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's just a cursory review. I haven't looked deep into implementation yet, but it looks good.
Though formatting differs from used in other crates. But it's my fault, as I haven't got time to make rustfmt config. (personally I am not fond of multiline approach of rustfmt)
Also, please add LICENSE files as in other crates.
@@ -0,0 +1,18 @@ | |||
[package] | |||
name = "grostl" | |||
version = "0.3.0" |
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's better to start from 0.1.0 as we don't require version synchronization across crates.
authors = ["The Rust-Crypto Project Developers"] | ||
license = "MIT/Apache-2.0" | ||
description = "Grostl hash function" | ||
documentation = "https://docs.rs/md5" |
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.
Wrong link to docs.
use generic_array::typenum::{Quot, U8}; | ||
use matrix::Matrix; | ||
|
||
const SBOX: [u8; 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.
I think it's better to move constants to the separate module, in other crates I've used consts.rs
for this purpose.
const SHIFTS_Q_WIDE: [u8; 8] = [1, 3, 5, 11, 0, 2, 4, 6]; | ||
|
||
pub struct Grostl<OutputSize, BlockSize: ArrayLength<u8>> | ||
where BlockSize::ArrayType: Copy |
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.
Add #[derive(Copy, Clone)]
to Grostl
and GrostlState
. You'll need to add several BlockSize::ArrayType: Copy
trait bounds for that to work.
let block_bytes = BlockSize::to_usize(); | ||
if block_bytes == 64 { | ||
false | ||
} else { |
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 use match statement with unreachable!
macro?
#[cfg(test)] | ||
mod test { | ||
use super::{xor_generic_array, C_P, C_Q, Grostl, SHIFTS_P}; | ||
use generic_array::typenum::{U32, U64}; |
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 think it's better to move this test module to the tests.rs
and use:
#[cfg(test)]
mod tests
In the lib.rs
.
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.
On the second thought it will require to make tested methods public, they still will not be accessible to the crate user as grostl
field will be private, but perhaps it's better to leave it as is. Your choice.
|
||
struct GrostlState<OutputSize, BlockSize: ArrayLength<u8>> { | ||
state: GenericArray<u8, BlockSize>, | ||
rounds: 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.
You also can impl Default
for GrostlState
. This will allow you to simplify code and tests a bit and you will be able to simply use #[derive(Default)]
on Grostl
.
extern crate grostl; | ||
|
||
use crypto_tests::hash::{Test, main_test}; | ||
use generic_array::typenum::{U28, U32, U48, U64}; |
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.
You can use type aliases instead of using GrostlSmall
and GrostlBig
directly. In my opinion it will look a bit nicer.
By the way, correct name for Grøstl is Groestl, not Grostl. So it's better to rename crate. :) Adding "grostl" to kewords should help with searchability. |
Ok, I believe I've addressed all of your comments. The crate and all structs should be renamed, the Small/Big issue should be fixed, and the other minor code changes were made. I decided to leave the tests in the same mod, as those were unit tests which need access to the private functions. The tests in I still need to add some tests to ensure the padding is correct, I haven't convinced myself that it is. I'm also planning on adding a benchmark, as I see there's one in the utils crate. Also, what names do I put for the copyright in the LICENSE file? My own? |
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.
Several minor comments.
@@ -0,0 +1,27 @@ | |||
Copyright (c) 2006-2009 Graydon Hoare | |||
Copyright (c) 2009-2013 Mozilla Foundation | |||
Copyright (c) 2016 Artyom Pavlov |
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's your work, so it's better to attribute yourself.
fn result(mut self) -> GenericArray<u8, Self::OutputSize> { | ||
self.buffer.next(1)[0] = 128; | ||
if self.buffer.remaining() >= 8 { | ||
let block_bytes = self.block_bytes(); |
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.
You can use standard_padding
method from digest-buffer
to reduce amount of code.
|
||
impl<OutputSize, BlockSize> Digest for Groestl<OutputSize, BlockSize> | ||
where OutputSize: ArrayLength<u8>, | ||
BlockSize: ArrayLength<u8> + Div<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.
Not sure if it's worth to implement Digest
for Groestl
. You can move input
and result
to struct's impl
. It'll reduce amount of code a bit.
#[test] | ||
fn test_shift_bytes() { | ||
let g: Groestl<U32, U64> = Groestl::default(); | ||
let s = g.state; |
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.
You do not use g
anywhere after that. Maybe just write let s = GroestlState::<U32, U64>::default();
? The same goes for other tests as well.
48, 57, 2, 11, 20, 29, 38, 47, | ||
56, 1, 10, 19, 28, 37, 46, 55, | ||
]; | ||
assert_eq!(&*block, &expected[..]); |
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.
You can write it as assert_eq!(&block[..], &expected[..]);
, which will be a bit clearer in my opinion. The same goes for other tests. I'll probably create later PR for generic-array
with implementation of PartialEq<[T]>
.
//! let mut hasher = GroestlBig::<U52>::new(); | ||
//! hasher.input(b"my message"); | ||
//! let result = hasher.result(); | ||
//!} |
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.
Unnecessary }
.
//! ``` | ||
//! | ||
//! ```rust,ignore | ||
//! use groestl::{Digest, Groestl256}; |
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.
Should be GroestlSmall
and GroestlBig
, not Groestl256
.
mod matrix; | ||
|
||
#[derive(Default)] | ||
pub struct GroestlSmall<OutputSize> |
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.
You forgot to derive Copy
and Clone
.
} | ||
|
||
#[derive(Default)] | ||
pub struct GroestlBig<OutputSize> |
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.
Copy
and Clone
.
Ok, I made those changes and I added some benchmarks. Since I'm using the |
Thank you for you work! Unfortunately performance is a bit lower than I expected (slightly less than 1 MB/s), but I will leave it for future improvements, I'll add your links to the related issue. I will publish this crate in the next few days. |
Add AArch64 sha1 and sha2 extension support
This PR contains an implementation of Grostl. I mainly used this document as a reference for implementation. This page contains a guide for different optimizations one can do in an implementation, as well as many optimized reference implementations, but I chose to implement none of these. The goal of my implementation is that it should be correct, readable, and well tested. This is because none of the other implementations are readable or well-tested, which made using them as a reference difficult. After this is merged, we can work on optimizations, as we'd have a nice reference implementation to test against.
One way Grostl differs from most other hash functions is that it allows you to specify a variable digest size between 1 and 64 bytes. However the block size is different between digests of size 1 to 32 and 33 to 64. In order to prevent people from using the wrong block size, I've added
GrostlSmall
andGrostlBig
which should prevent you from making this mistake when you specify your customOutputSize
. I've also provided type aliases for the common digest sizes, 224, 256, 384, and 512.While the code is done, two minor things I plan on adding are more comments/documentation, more/better tests (especially around edge cases like padding), and cleaning up some of the assertions. It should be fine for you to start reviewing now, as these are minor changes.