Skip to content

Change Sha2::Digest to make {:x} easier (hex format) #102

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

Closed
gjvnq opened this issue Feb 23, 2020 · 5 comments
Closed

Change Sha2::Digest to make {:x} easier (hex format) #102

gjvnq opened this issue Feb 23, 2020 · 5 comments

Comments

@gjvnq
Copy link

gjvnq commented Feb 23, 2020

Hi, I was writing a simple program and I discovered that getting a hex output of a generic hash is harder than I thought.

I expected that something like this would work:

extern crate sha2;
use sha2::Digest;

fn example<D: Digest>() {
    let mut hasher = D::new();
    hasher.input(b"hello world");
    let hash = hasher.result();
    println!("{:x}", hash);
}

However, the above code generates the following error:

error[E0277]: cannot add `<D as sha2::Digest>::OutputSize` to `<D as sha2::Digest>::OutputSize`
   --> src/main.rs:103:22
    |
99  | fn example<D: Digest>() {
    |                        - help: consider further restricting the associated type: `where <D as sha2::Digest>::OutputSize: std::ops::Add`
...
103 |     println!("{:x}", hash);
    |                      ^^^^ no implementation for `<D as sha2::Digest>::OutputSize + <D as sha2::Digest>::OutputSize`
    |
    = help: the trait `std::ops::Add` is not implemented for `<D as sha2::Digest>::OutputSize`
    = note: required because of the requirements on the impl of `std::fmt::LowerHex` for `sha2::digest::generic_array::GenericArray<u8, <D as sha2::Digest>::OutputSize>`
    = note: required by `std::fmt::LowerHex::fmt`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

After some experimentation, I discovered that the following code does work:

extern crate sha2;
use sha2::Digest;

fn example<D: Digest>() where <D as sha2::Digest>::OutputSize: std::ops::Add, <<D as sha2::Digest>::OutputSize as std::ops::Add>::Output: sha2::digest::generic_array::ArrayLength<u8>   {
    let mut hasher = D::new();
    hasher.input(b"hello world");
    let hash = hasher.result();
    println!("{:x}", hash);
}

So, I think that the Digest trait should be changed to make the extra code unecessary.

@tarcieri
Copy link
Member

Wow, those are some wacky trait bound requirements!

This seems like an unfortunate complication of generic-array. I wonder if newer versions of generic-array than the one it’s presently using (v0.12) are any better...

@tarcieri
Copy link
Member

@gjvnq do you really need something that’s generic around Digest? If not, you can use the concrete Sha256 type instead, which should eliminate the generic parameter and therefore the associated trait bounds.

@gjvnq
Copy link
Author

gjvnq commented Feb 24, 2020

Yes, I have a function like this:

fn do_backup(source: &Path, storage: &Path, alg: Digest)

However, I changed to OpenSSL to get hardware acceleration.

@newpavlov
Copy link
Member

newpavlov commented Jun 19, 2020

@gjvnq
FYI: we have added hardware acceleration support for SHA-1 and SHA-256.

@newpavlov
Copy link
Member

newpavlov commented Jun 19, 2020

Overall I am not sure if it's worth to complicate Digest for such corner case. The following signature is annoying, but will work in practice:

use digest::Digest;
use digest::generic_array::ArrayLength;
use std::ops::Add;

fn example<D>()
    where D: Digest, D::OutputSize: Add,
        <D::OutputSize as Add>::Output: ArrayLength<u8>
{ .. }

And personally I would use the hex crate instead of relying on formatting support from generic-array. Note that in future we will migrate to const generics and support of {:x} will disappear either way.

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

No branches or pull requests

3 participants