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

Implements hashing as a blanket trait for instances of CanonicalSerialize #265

Merged
merged 5 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion serialize/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@ edition = "2018"
[dependencies]
ark-serialize-derive = { version = "^0.2.0", path = "../serialize-derive", optional = true }
ark-std = { version = "0.2.0", default-features = false }
digest = { version = "0.9", default-features = false }

[dev-dependencies]
sha2 = { version = "0.9.3", default-features = false}
sha3 = { version = "0.9.1", default-features = false}
blake2 = { version = "0.9.1", default-features = false}

[features]
default = []
std = [ "ark-std/std" ]
std = [ "ark-std/std", ]
derive = [ "ark-serialize-derive" ]
81 changes: 81 additions & 0 deletions serialize/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub use flags::*;
#[doc(hidden)]
pub use ark_serialize_derive::*;

use digest::{generic_array::GenericArray, Digest};

/// Serializer in little endian format allowing to encode flags.
pub trait CanonicalSerializeWithFlags: CanonicalSerialize {
/// Serializes `self` and `flags` into `writer`.
Expand Down Expand Up @@ -94,6 +96,45 @@ pub trait CanonicalSerialize {
}
}

// This private struct works around Serialize taking the pre-existing
// std::io::Write instance of most digest::Digest implementations by value
struct HashMarshaller<'a, H: Digest>(&'a mut H);

impl<'a, H: Digest> ark_std::io::Write for HashMarshaller<'a, H> {
#[inline]
fn write(&mut self, buf: &[u8]) -> ark_std::io::Result<usize> {
Digest::update(self.0, buf);
Ok(buf.len())
}

#[inline]
fn flush(&mut self) -> ark_std::io::Result<()> {
Ok(())
}
}

/// The CanonicalSerialize induces a natural way to hash the
/// corresponding value, of which this is the convenience trait.
pub trait CanonicalSerializeHashExt: CanonicalSerialize {
fn hash<H: Digest>(&self) -> GenericArray<u8, <H as Digest>::OutputSize> {
let mut hasher = H::new();
self.serialize(HashMarshaller(&mut hasher))
.expect("HashMarshaller::flush should be infaillible!");
hasher.finalize()
}

fn hash_uncompressed<H: Digest>(&self) -> GenericArray<u8, <H as Digest>::OutputSize> {
let mut hasher = H::new();
self.serialize_uncompressed(HashMarshaller(&mut hasher))
.expect("HashMarshaller::flush should be infaillible!");
hasher.finalize()
}
}

/// CanonicalSerializeHashExt is a (blanket) extension trait of
/// CanonicalSerialize
impl<T: CanonicalSerialize> CanonicalSerializeHashExt for T {}

/// Deserializer in little endian format allowing flags to be encoded.
pub trait CanonicalDeserializeWithFlags: Sized {
/// Reads `Self` and `Flags` from `reader`.
Expand Down Expand Up @@ -897,6 +938,28 @@ mod test {
assert_eq!(data, de);
}

fn test_hash<T: CanonicalSerialize, H: Digest + core::fmt::Debug>(data: T) {
let h1 = data.hash::<H>();

let mut hash = H::new();
let mut serialized = vec![0; data.serialized_size()];
data.serialize(&mut serialized[..]).unwrap();
hash.update(&serialized);
let h2 = hash.finalize();

assert_eq!(h1, h2);

let h3 = data.hash_uncompressed::<H>();

let mut hash = H::new();
serialized = vec![0; data.uncompressed_size()];
data.serialize_uncompressed(&mut serialized[..]).unwrap();
hash.update(&serialized);
let h4 = hash.finalize();

assert_eq!(h3, h4);
}

// Serialize T, randomly mutate the data, and deserialize it.
// Ensure it fails.
// Up to the caller to provide a valid mutation criterion
Expand Down Expand Up @@ -1024,4 +1087,22 @@ mod test {
fn test_phantomdata() {
test_serialize(core::marker::PhantomData::<Dummy>);
}

#[test]
fn test_sha2() {
test_hash::<_, sha2::Sha256>(Dummy);
test_hash::<_, sha2::Sha512>(Dummy);
}

#[test]
fn test_blake2() {
test_hash::<_, blake2::Blake2b>(Dummy);
test_hash::<_, blake2::Blake2s>(Dummy);
}

#[test]
fn test_sha3() {
test_hash::<_, sha3::Sha3_256>(Dummy);
test_hash::<_, sha3::Sha3_512>(Dummy);
}
}