Implement std::hash::Hasher + Clone for digests

Closes #20

Change-Id: Ib150970ce3793a6fbeb8d26bc98e7ef013dcec00
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 93f926e..ea9a435 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@
   `constant_time_eq`.
 - `hmac::Hmac` now implements `Clone` and `std::hash::Hasher`, allowing it to be
   used with any type that implements `std::hash::Hash`.
+- `hash::Hasher` now similarly implies `Clone` and `std::hash::Hasher`.
 
 ### Changed
 - `build.rs` implements symbol name scraping natively, and no longer relies on
diff --git a/src/boringssl/mod.rs b/src/boringssl/mod.rs
index 84f99be..29a1b0e 100644
--- a/src/boringssl/mod.rs
+++ b/src/boringssl/mod.rs
@@ -792,6 +792,20 @@
     (@doc_string $s:expr) => (#[doc="The `"] #[doc=$s] #[doc="` function."]);
 }
 
+/// Implements `Clone` for a `CStackWrapper<T>`.
+///
+/// Unsound for types without no-op `CDestruct` impls, or which
+/// capture `!Sync` shared state.
+macro_rules! impl_clone {
+    ($ty: ty) => {
+        impl Clone for CStackWrapper<$ty> {
+            fn clone(&self) -> Self {
+                unsafe { CStackWrapper::new(*self.as_const()) }
+            }
+        }
+    };
+}
+
 impl_hash!(
     SHA_CTX,
     SHA_DIGEST_LENGTH,
@@ -802,6 +816,7 @@
     sha1_final,
     SHA1_Final
 );
+impl_clone!(SHA_CTX);
 impl_hash!(
     SHA256_CTX,
     SHA256_DIGEST_LENGTH,
@@ -812,6 +827,7 @@
     sha256_final,
     SHA256_Final
 );
+impl_clone!(SHA256_CTX);
 impl_hash!(
     SHA512_CTX,
     SHA384_DIGEST_LENGTH,
@@ -832,6 +848,7 @@
     sha512_final,
     SHA512_Final
 );
+impl_clone!(SHA512_CTX);
 
 /// The `CRYPTO_memcmp` function.
 ///
diff --git a/src/hash.rs b/src/hash.rs
index 4f2ca68..664821d 100644
--- a/src/hash.rs
+++ b/src/hash.rs
@@ -49,8 +49,13 @@
 }
 
 /// A cryptographic hash function.
+// We expose `Clone` because implementing `std::hash::Hasher` is
+// useful, and forces us to expose a `fn finish(&self)`. That exposes
+// the capacity to compute a digest based on the current state and
+// keep going, so providing no way to do that using the native API
+// serves only to force users to jump through hoops.
 #[must_use]
-pub trait Hasher: Default + self::inner::Hasher {
+pub trait Hasher: Default + Clone + std::hash::Hasher + self::inner::Hasher {
     /// The output digest.
     #[must_use]
     type Digest: Digest;
@@ -99,7 +104,7 @@
 // NOTE: InsecureSha1 is not publicly available; it is only used in HMAC-SHA1.
 #[cfg(feature = "insecure")]
 #[deprecated(note = "SHA-1 is considered insecure")]
-#[derive(Default)]
+#[derive(Clone, Default)]
 pub(crate) struct InsecureSha1 {
     ctx: CStackWrapper<boringssl::SHA_CTX>,
 }
@@ -119,7 +124,7 @@
 }
 
 /// The SHA-256 hash function.
-#[derive(Default)]
+#[derive(Clone, Default)]
 #[must_use]
 pub struct Sha256 {
     ctx: CStackWrapper<boringssl::SHA256_CTX>,
@@ -132,6 +137,7 @@
 pub struct Sha256Digest(pub(crate) [u8; boringssl::SHA256_DIGEST_LENGTH as usize]);
 
 /// The SHA-384 hash function.
+#[derive(Clone)]
 #[must_use]
 pub struct Sha384 {
     ctx: CStackWrapper<boringssl::SHA512_CTX>,
@@ -153,7 +159,7 @@
 pub struct Sha384Digest(pub(crate) [u8; boringssl::SHA384_DIGEST_LENGTH as usize]);
 
 /// The SHA-512 hash function.
-#[derive(Default)]
+#[derive(Clone, Default)]
 #[must_use]
 pub struct Sha512 {
     ctx: CStackWrapper<boringssl::SHA512_CTX>,
@@ -203,6 +209,23 @@
             }
         }
         #[allow(deprecated)]
+        impl std::hash::Hasher for $name {
+            fn write(&mut self, bytes: &[u8]) {
+                self.update(bytes);
+            }
+
+            fn finish(&self) -> u64 {
+                use self::inner::Digest;
+                let digest = self.clone().finish();
+                // Translate a digest to a u64 in an arbitrary
+                // reasonable way
+                let mut buf = [0; 8];
+                let len = digest.as_ref().len().min(8);
+                buf[0..len].copy_from_slice(&digest.as_ref()[0..len]);
+                u64::from_le_bytes(buf)
+            }
+        }
+        #[allow(deprecated)]
         impl self::inner::Digest for $digest_name {
             fn zero() -> Self {
                 $digest_name([0; $digest_len as usize])
@@ -295,6 +318,7 @@
     #[cfg(feature = "insecure")]
     use super::insecure_sha1_digest::*;
     use super::*;
+    use std::convert::TryInto;
 
     #[test]
     fn test_constants() {
@@ -330,10 +354,21 @@
             sha512: <Sha512 as Hasher>::Digest,
         }
 
+        fn std_hash<H: Hasher>(x: &[u8]) -> u64 {
+            let mut hasher = H::default();
+            hasher.write(x);
+            <H as std::hash::Hasher>::finish(&hasher)
+        }
+
         for case in TEST_CASES.iter() {
             fn test<H: Hasher>(input: &'static [u8], digest: &H::Digest) {
+                use self::inner::Digest;
                 let got = H::hash(input);
                 assert_eq!(&got, digest, "input: {:?}", input);
+                assert_eq!(
+                    std_hash::<H>(input),
+                    u64::from_le_bytes(digest.as_ref()[0..8].try_into().unwrap())
+                );
                 // Also use this as an opportunity to test Digest::from_bytes
                 // and Digest::as_ref.
                 assert_eq!(