Skip to content

Commit

Permalink
serialize Hash with serde_bytes
Browse files Browse the repository at this point in the history
Closes #412.
  • Loading branch information
oconnor663 committed Jul 10, 2024
1 parent 7ff6944 commit dd0afd6
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,16 @@ mmap = ["std", "dep:memmap2"]
# Implement the zeroize::Zeroize trait for types in this crate.
zeroize = ["dep:zeroize", "arrayvec/zeroize"]

serde = ["dep:serde", "dep:serde_bytes"]

# This crate implements traits from the RustCrypto project, exposed here as the
# "traits-preview" feature. However, these traits aren't stable, and they're
# expected to change in incompatible ways before they reach 1.0. For that
# reason, this crate makes no SemVer guarantees for this feature, and callers
# who use it should expect breaking changes between patch versions of this
# crate. (The "*-preview" feature name follows the conventions of the RustCrypto
# "signature" crate.)
traits-preview = ["digest"]
traits-preview = ["dep:digest"]

# ---------- Features below this line are undocumented and unstable. ----------
# The following features are mainly intended for testing and benchmarking, and
Expand Down Expand Up @@ -103,6 +105,7 @@ digest = { version = "0.10.1", features = [ "mac" ], optional = true }
memmap2 = { version = "0.9", optional = true }
rayon-core = { version = "1.12.1", optional = true }
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
serde_bytes = { version = "0.11.15", optional = true }
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"], optional = true }

[dev-dependencies]
Expand All @@ -114,6 +117,7 @@ rand_chacha = "0.3.0"
reference_impl = { path = "./reference_impl" }
tempfile = "3.8.0"
serde_json = "1.0.107"
ciborium = "0.2.2"

[build-dependencies]
cc = "1.0.4"
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,12 @@ fn counter_high(counter: u64) -> u32 {
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Hash)]
pub struct Hash([u8; OUT_LEN]);
pub struct Hash(
#[rustfmt::skip]
// In formats like CBOR, bytestrings are more compact than lists of ints.
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
[u8; OUT_LEN],
);

impl Hash {
/// The raw bytes of the `Hash`. Note that byte arrays don't provide
Expand Down
28 changes: 26 additions & 2 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,14 +809,38 @@ fn test_mmap_rayon() -> Result<(), std::io::Error> {
#[cfg(feature = "std")]
#[cfg(feature = "serde")]
fn test_serde() {
let hash: crate::Hash = [7; 32].into();
let hash: crate::Hash = [255; 32].into();

let json = serde_json::to_string(&hash).unwrap();
assert_eq!(
json,
"[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7]",
"[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]",
);
let hash2: crate::Hash = serde_json::from_str(&json).unwrap();
assert_eq!(hash, hash2);

let mut cbor = Vec::<u8>::new();
ciborium::into_writer(&hash, &mut cbor).unwrap();
assert_eq!(
cbor,
[
88, 32, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
]
);
let hash_from_cbor: crate::Hash = ciborium::from_reader(&cbor[..]).unwrap();
assert_eq!(hash_from_cbor, hash);

// Before we used serde_bytes, the hash [255; 32] would serialize as an array instead of a
// byte string, like this. Make sure we can still deserialize this representation.
let old_cbor: &[u8] = &[
152, 32, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255,
24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255,
24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255, 24, 255,
24, 255, 24, 255, 24, 255,
];
let hash_from_old_cbor: crate::Hash = ciborium::from_reader(old_cbor).unwrap();
assert_eq!(hash_from_old_cbor, hash);
}

// `cargo +nightly miri test` currently works, but it takes forever, because some of our test
Expand Down

0 comments on commit dd0afd6

Please sign in to comment.