Skip to content
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

A cryptographically sound Hash trait #13

Closed
mzabaluev opened this issue Dec 9, 2017 · 5 comments
Closed

A cryptographically sound Hash trait #13

mzabaluev opened this issue Dec 9, 2017 · 5 comments

Comments

@mzabaluev
Copy link

It would be useful to be able to define the way to calculate a digest over a data structure. A naive approach would be to implement the widely supported and derivable core trait Hash, provide a complementary Hasher implementation backed by a digest function, and ignore the Hasher::finish() method, going for the underlying digest output instead. Unfortunately, the standard Hash/Hasher are not designed to support machine- and language-independent hashing: it's allowed to hash isize/usize, and for whatever reason, the Hash implementation for slice differs from feeding the slice content in sequence to an equivalent Hasher.

Therefore, digest or a related crate could provide a cryptography-friendly alternative, with at least the following features:

  • using a digest::Input as the recipient instead of std::hash::Hasher;
  • making the standard sequential containers transparent for hashing;
  • principally not providing Hash implementations for machine-dependent primitive types.

In full realization, a procedural macro can be provided to derive implementations similar to how it's done with the standard Hash.

Being able to specify the byte order for wider integer fields as compile-time choice should work somewhere in the API, but I'm unsure whether it makes sense for types to control which byte order they want for hashing with their choice of impls (e.g. a type could implement only Hash<LittleEndian>), or would it be better to delegate it to a hasher adapter.

@tarcieri
Copy link
Member

tarcieri commented Dec 9, 2017

You might want to take a look at ObjectHash:

https://github.com/cryptosphere/objecthash-rs

Specifically the ObjectHasher and ObjectHash traits:

https://github.com/cryptosphere/objecthash-rs/blob/master/src/lib.rs#L49

@newpavlov
Copy link
Member

It was discussed at length earlier here. We have decided that it's better to develop struct hashing as a separate crate which will depend on digest.

I've reopened this issue in the utils repository. It's not the best place for this issue, but it's probably not for hashes repo either.

@mzabaluev
Copy link
Author

At least a trait like this should be added to digest to support the Hash trait, and may appear in a PR soon:

extern crate byteorder;

use byteorder::ByteOrder;
use std::mem;

macro_rules! endian_method {
    ($name:ident($t:ty), $bo_func:ident) => {
        fn $name(&mut self, n: $t) {
            let mut buf: [u8; mem::size_of::<$t>()]
                         = unsafe { mem::uninitialized() };
            Bo::$bo_func(&mut buf, n);
            self.process(&buf);
        }
    }
}

pub trait EndianInput<Bo> : Input
    where Bo: ByteOrder
{
    fn process_u8(&mut self, n: u8) {
        self.process(&[n]);
    }

    fn process_i8(&mut self, n: i8) {
        self.process(&[n as u8]);
    }

    endian_method!(process_u16(u16), write_u16);
    endian_method!(process_i16(i16), write_i16);
    endian_method!(process_u32(u32), write_u32);
    endian_method!(process_i32(i32), write_i32);
    endian_method!(process_u64(u64), write_u64);
    endian_method!(process_i64(i64), write_i64);
    endian_method!(process_f32(f32), write_f32);
    endian_method!(process_f64(f64), write_f64);
}

@newpavlov
Copy link
Member

newpavlov commented Dec 9, 2017

I think it's better to proceed with an extension trait implemented in a separate crate for all digest::Input implementations, I don't see why this trait should be a part of the digest crate.

@mzabaluev
Copy link
Author

mzabaluev commented Dec 9, 2017

Perhaps, together with the hash trait and the procedural macro to generate impls.

Could you post a brief recap of the serde-related discussion here as well? Is Serialize a good fit for machine-independent representations, or should the hashing backend make do with lots of unimplemented! to backstop non-portable hash implementations?

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