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

Hardcode usage of sha2::Sha512 #64

Closed
isislovecruft opened this issue Dec 24, 2018 · 1 comment
Closed

Hardcode usage of sha2::Sha512 #64

isislovecruft opened this issue Dec 24, 2018 · 1 comment
Assignees

Comments

@isislovecruft
Copy link
Member

isislovecruft commented Dec 24, 2018

RFC8032 specifies using SHA2-512 as the hash digest, however this library requires only a hash digest implementation with 512-bits of output. This was intended to leave the implementation to the user, for users with more finicky needs such as tor---who wished to wrap their usage of OpenSSL's digest (ticket #24659) and (P)RNG implementation in Rust and pass these interfaces to ed25519-dalek in order to reduce vulnerability surface and audit requirements. This is somewhat silly for the case of hashes, as an incorrect hash implementation is trivially detectable (e.g. the ed25519-dalek test suite will not pass). And while I did originally have the idea that this library could be used in a more "generalised EdDSA" sense (e.g. with Blake2b), this does not encompass the full set of generalisations which are optimal and desirable (e.g. configurable and automated domain separations, extensible signature, zero-knowledge proof composability, etc.).

With this in mind, I'd like to hardcode the usage of sha2 instance to be sha2::Sha512. Users who wish to replace it for whatever reason may still do so with by creating a "sha2" crate with a "Sha512" type implementing the correct traits from the digest crate with:

[patch.crates-io]
sha2 = { git = "https://github.com/your-name-here/alternate-sha2.git" }
@isislovecruft isislovecruft self-assigned this Dec 24, 2018
isislovecruft added a commit to isislovecruft/ed25519-dalek that referenced this issue Dec 29, 2018
This implements dalek-cryptography#64

You can still choose the "prehash" algorithm, as long as it has 64 bytes of
output.  Otherwise, everything is hardcoded to use sha2::Sha512.  To use a
different implementation you'll need a [patch.crates-io] section in cargo
config.

diff --git c/Cargo.toml i/Cargo.toml
index 5b04835..5d5cc94 100644
--- c/Cargo.toml
+++ i/Cargo.toml
@@ -22,40 +22,39 @@ default-features = false
 [dependencies.rand]
 version = "0.6"
 features = ["i128_support"]

 [dependencies.serde]
 version = "^1.0"
 optional = true

 [dependencies.sha2]
 version = "^0.8"
-optional = true
+default-features = false

 [dependencies.failure]
 version = "^0.1.1"
 default-features = false

 [dependencies.clear_on_drop]
 version = "0.2"

 [dev-dependencies]
 hex = "^0.3"
-sha2 = "^0.8"
 bincode = "^0.9"
 criterion = "0.2"

 [[bench]]
 name = "ed25519_benchmarks"
 harness = false

 [features]
 default = ["std", "u64_backend"]
 # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies.
-std = ["curve25519-dalek/std", "rand/std"]
+std = ["curve25519-dalek/std", "rand/std", "sha2/std"]
 alloc = ["curve25519-dalek/alloc"]
 nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"]
 asm = ["sha2/asm"]
 yolocrypto = ["curve25519-dalek/yolocrypto"]
 u64_backend = ["curve25519-dalek/u64_backend"]
 u32_backend = ["curve25519-dalek/u32_backend"]
 avx2_backend = ["curve25519-dalek/avx2_backend"]
diff --git c/src/ed25519.rs i/src/ed25519.rs
index 4d2fabd..c7f5c69 100644
--- c/src/ed25519.rs
+++ i/src/ed25519.rs
@@ -1,43 +1,41 @@
 // -*- mode: rust; -*-
 //
 // This file is part of ed25519-dalek.
 // Copyright (c) 2017-2018 Isis Lovecruft
 // See LICENSE for licensing information.
 //
 // Authors:
 // - Isis Agora Lovecruft <isis@patternsinthevoid.net>

-//! A Rust implementation of ed25519 EdDSA key generation, signing, and
-//! verification.
+//! A Rust implementation of ed25519 key generation, signing, and verification.

 use core::default::Default;
 use core::fmt::{Debug};

 use rand::CryptoRng;
 use rand::Rng;

 #[cfg(feature = "serde")]
 use serde::{Serialize, Deserialize};
 #[cfg(feature = "serde")]
 use serde::{Serializer, Deserializer};
 #[cfg(feature = "serde")]
 use serde::de::Error as SerdeError;
 #[cfg(feature = "serde")]
 use serde::de::Visitor;

-#[cfg(feature = "sha2")]
-use sha2::Sha512;
+pub use sha2::Sha512;

 use clear_on_drop::clear::Clear;

-use curve25519_dalek::digest::Digest;
+pub use curve25519_dalek::digest::Digest;
 use curve25519_dalek::digest::generic_array::typenum::U64;

 use curve25519_dalek::constants;
 use curve25519_dalek::edwards::CompressedEdwardsY;
 use curve25519_dalek::edwards::EdwardsPoint;
 use curve25519_dalek::scalar::Scalar;

 use errors::SignatureError;
 use errors::InternalError;

@@ -181,27 +179,20 @@ impl Drop for SecretKey {
     }
 }

 impl AsRef<[u8]> for SecretKey {
     fn as_ref(&self) -> &[u8] {
         self.as_bytes()
     }
 }

 impl SecretKey {
-    /// Expand this `SecretKey` into an `ExpandedSecretKey`.
-    pub fn expand<D>(&self) -> ExpandedSecretKey
-        where D: Digest<OutputSize = U64> + Default
-    {
-        ExpandedSecretKey::from_secret_key::<D>(&self)
-    }
-
     /// Convert this secret key to a byte array.
     #[inline]
     pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
         self.0
     }

     /// View this secret key as a byte array.
     #[inline]
     pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] {
         &self.0
@@ -272,52 +263,44 @@ impl SecretKey {
     /// use ed25519_dalek::Signature;
     ///
     /// let mut csprng: OsRng = OsRng::new().unwrap();
     /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     /// # }
     /// #
     /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
-    /// Afterwards, you can generate the corresponding public—provided you also
-    /// supply a hash function which implements the `Digest` and `Default`
-    /// traits, and which returns 512 bits of output—via:
+    /// Afterwards, you can generate the corresponding public:
     ///
     /// ```
     /// # extern crate rand;
-    /// # extern crate sha2;
     /// # extern crate ed25519_dalek;
     /// #
     /// # fn main() {
     /// #
     /// # use rand::Rng;
     /// # use rand::thread_rng;
-    /// # use sha2::Sha512;
     /// # use ed25519_dalek::PublicKey;
     /// # use ed25519_dalek::SecretKey;
     /// # use ed25519_dalek::Signature;
     /// #
     /// # let mut csprng = thread_rng();
     /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     ///
-    /// let public_key: PublicKey = PublicKey::from_secret::<Sha512>(&secret_key);
+    /// let public_key: PublicKey = (&secret_key).into();
     /// # }
     /// ```
     ///
-    /// The standard hash function used for most ed25519 libraries is SHA-512,
-    /// which is available with `use sha2::Sha512` as in the example above.
-    /// Other suitable hash functions include Keccak-512 and Blake2b-512.
-    ///
     /// # Input
     ///
-    /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`
+    /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng`
     pub fn generate<T>(csprng: &mut T) -> SecretKey
         where T: CryptoRng + Rng,
     {
         let mut sk: SecretKey = SecretKey([0u8; 32]);

         csprng.fill_bytes(&mut sk.0);

         sk
     }
 }
@@ -391,49 +374,59 @@ pub struct ExpandedSecretKey {
 }

 /// Overwrite secret key material with null bytes when it goes out of scope.
 impl Drop for ExpandedSecretKey {
     fn drop(&mut self) {
         self.key.clear();
         self.nonce.clear();
     }
 }

-#[cfg(feature = "sha2")]
 impl<'a> From<&'a SecretKey> for ExpandedSecretKey {
     /// Construct an `ExpandedSecretKey` from a `SecretKey`.
     ///
     /// # Examples
     ///
     /// ```
     /// # extern crate rand;
     /// # extern crate sha2;
     /// # extern crate ed25519_dalek;
     /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
     /// # fn main() {
     /// #
     /// use rand::Rng;
-    /// use rand::rngs::OsRng;
+    /// use rand::thread_rng;
     /// use sha2::Sha512;
     /// use ed25519_dalek::{SecretKey, ExpandedSecretKey};
     ///
-    /// let mut csprng: OsRng = OsRng::new().unwrap();
+    /// let mut csprng = thread_rng();
     /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key);
     /// # }
-    /// #
-    /// # #[cfg(any(not(feature = "std"), not(feature = "sha2")))]
-    /// # fn main() {}
     /// ```
     fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey {
-        ExpandedSecretKey::from_secret_key::<Sha512>(&secret_key)
+        let mut h: Sha512 = Sha512::default();
+        let mut hash:  [u8; 64] = [0u8; 64];
+        let mut lower: [u8; 32] = [0u8; 32];
+        let mut upper: [u8; 32] = [0u8; 32];
+
+        h.input(secret_key.as_bytes());
+        hash.copy_from_slice(h.result().as_slice());
+
+        lower.copy_from_slice(&hash[00..32]);
+        upper.copy_from_slice(&hash[32..64]);
+
+        lower[0]  &= 248;
+        lower[31] &=  63;
+        lower[31] |=  64;
+
+        ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, }
     }
 }

 impl ExpandedSecretKey {
     /// Convert this `ExpandedSecretKey` into an array of 64 bytes.
     ///
     /// # Returns
     ///
     /// An array of 64 bytes.  The first 32 bytes represent the "expanded"
     /// secret key, and the last 32 bytes represent the "domain-separation"
@@ -525,82 +518,36 @@ impl ExpandedSecretKey {
         let mut lower: [u8; 32] = [0u8; 32];
         let mut upper: [u8; 32] = [0u8; 32];

         lower.copy_from_slice(&bytes[00..32]);
         upper.copy_from_slice(&bytes[32..64]);

         Ok(ExpandedSecretKey{ key:   Scalar::from_bits(lower),
                               nonce:                   upper  })
     }

-    /// Construct an `ExpandedSecretKey` from a `SecretKey`, using hash function `D`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # extern crate rand;
-    /// # extern crate sha2;
-    /// # extern crate ed25519_dalek;
-    /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
-    /// # fn main() {
-    /// #
-    /// use rand::Rng;
-    /// use rand::rngs::OsRng;
-    /// use sha2::Sha512;
-    /// use ed25519_dalek::{SecretKey, ExpandedSecretKey};
-    ///
-    /// let mut csprng: OsRng = OsRng::new().unwrap();
-    /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
-    /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::<Sha512>(&secret_key);
-    /// # }
-    /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
-    /// # fn main() { }
-    /// ```
-    pub fn from_secret_key<D>(secret_key: &SecretKey) -> ExpandedSecretKey
-            where D: Digest<OutputSize = U64> + Default {
-        let mut h: D = D::default();
-        let mut hash:  [u8; 64] = [0u8; 64];
-        let mut lower: [u8; 32] = [0u8; 32];
-        let mut upper: [u8; 32] = [0u8; 32];
-
-        h.input(secret_key.as_bytes());
-        hash.copy_from_slice(h.result().as_slice());
-
-        lower.copy_from_slice(&hash[00..32]);
-        upper.copy_from_slice(&hash[32..64]);
-
-        lower[0]  &= 248;
-        lower[31] &=  63;
-        lower[31] |=  64;
-
-        ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, }
-    }
-
     /// Sign a message with this `ExpandedSecretKey`.
     #[allow(non_snake_case)]
-    pub fn sign<D>(&self, message: &[u8], public_key: &PublicKey) -> Signature
-            where D: Digest<OutputSize = U64> + Default {
-        let mut h: D = D::default();
+    pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature {
+        let mut h: Sha512 = Sha512::new();
         let R: CompressedEdwardsY;
         let r: Scalar;
         let s: Scalar;
         let k: Scalar;

         h.input(&self.nonce);
         h.input(&message);

         r = Scalar::from_hash(h);
         R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();

-        h = D::default();
+        h = Sha512::new();
         h.input(R.as_bytes());
         h.input(public_key.as_bytes());
         h.input(&message);

         k = Scalar::from_hash(h);
         s = &(&k * &self.key) + &r;

         Signature{ R, s }
     }

@@ -616,27 +563,30 @@ impl ExpandedSecretKey {
     /// * `context` is an optional context string, up to 255 bytes inclusive,
     ///   which may be used to provide additional domain separation.  If not
     ///   set, this will default to an empty string.
     ///
     /// # Returns
     ///
     /// An Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     #[allow(non_snake_case)]
-    pub fn sign_prehashed<D>(&self,
-                             prehashed_message: D,
-                             public_key: &PublicKey,
-                             context: Option<&'static [u8]>) -> Signature
-        where D: Digest<OutputSize = U64> + Default
+    pub fn sign_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        public_key: &PublicKey,
+        context: Option<&'static [u8]>,
+    ) -> Signature
+        where
+            D: Digest<OutputSize = U64>,
     {
-        let mut h: D;
+        let mut h: Sha512;
         let mut prehash: [u8; 64] = [0u8; 64];
         let R: CompressedEdwardsY;
         let r: Scalar;
         let s: Scalar;
         let k: Scalar;

         let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string.

         debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");

@@ -650,32 +600,32 @@ impl ExpandedSecretKey {
         // the upper half "prefix" of the hashed "secret key" in here?  Why
         // can't the user just supply their own nonce and decide for themselves
         // whether or not they want a deterministic signature scheme?  Why does
         // the message go into what's ostensibly the signature domain separation
         // hash?  Why wasn't there always a way to provide a context string?
         //
         // ...
         //
         // This is a really fucking stupid bandaid, and the damned scheme is
         // still bleeding from malleability, for fuck's sake.
-        h = D::default()
+        h = Sha512::new()
             .chain(b"SigEd25519 no Ed25519 collisions")
             .chain(&[1]) // Ed25519ph
             .chain(&[ctx_len])
             .chain(ctx)
             .chain(&self.nonce)
             .chain(&prehash[..]);

         r = Scalar::from_hash(h);
         R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();

-        h = D::default()
+        h = Sha512::new()
             .chain(b"SigEd25519 no Ed25519 collisions")
             .chain(&[1]) // Ed25519ph
             .chain(&[ctx_len])
             .chain(ctx)
             .chain(R.as_bytes())
             .chain(public_key.as_bytes())
             .chain(&prehash[..]);

         k = Scalar::from_hash(h);
         s = &(&k * &self.key) + &r;
@@ -787,69 +737,75 @@ impl PublicKey {
                 name: "PublicKey", length: PUBLIC_KEY_LENGTH }));
         }
         let mut bits: [u8; 32] = [0u8; 32];
         bits.copy_from_slice(&bytes[..32]);

         let compressed = CompressedEdwardsY(bits);
         let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?;

         Ok(PublicKey(compressed, point))
     }
+}

+impl<'a> From<&'a SecretKey> for PublicKey {
     /// Derive this public key from its corresponding `SecretKey`.
-    #[allow(unused_assignments)]
-    pub fn from_secret<D>(secret_key: &SecretKey) -> PublicKey
-        where D: Digest<OutputSize = U64> + Default
-    {
-        let mut h:    D = D::default();
+    fn from(secret_key: &SecretKey) -> PublicKey {
+        let mut h:    Sha512 = Sha512::new();
         let mut hash:   [u8; 64] = [0u8; 64];
         let mut digest: [u8; 32] = [0u8; 32];

         h.input(secret_key.as_bytes());
         hash.copy_from_slice(h.result().as_slice());

         digest.copy_from_slice(&hash[..32]);

         PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest)
     }
+}

+impl<'a> From<&'a ExpandedSecretKey> for PublicKey {
     /// Derive this public key from its corresponding `ExpandedSecretKey`.
-    pub fn from_expanded_secret(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
+    fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
         let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes();

         PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits)
     }
+}

+impl PublicKey {
     /// Internal utility function for mangling the bits of a (formerly
     /// mathematically well-defined) "scalar" and multiplying it to produce a
     /// public key.
     fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey {
         bits[0]  &= 248;
         bits[31] &= 127;
         bits[31] |= 64;

         let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE;
         let compressed = point.compress();

         PublicKey(compressed, point)
     }

     /// Verify a signature on a message with this keypair's public key.
     ///
     /// # Return
     ///
     /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
     #[allow(non_snake_case)]
-    pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError>
-            where D: Digest<OutputSize = U64> + Default
+    pub fn verify(
+        &self,
+        message: &[u8],
+        signature: &Signature
+    ) -> Result<(), SignatureError>
     {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::new();
         let R: EdwardsPoint;
         let k: Scalar;
         let minus_A: EdwardsPoint = -self.1;

         h.input(signature.R.as_bytes());
         h.input(self.as_bytes());
         h.input(&message);

         k = Scalar::from_hash(h);
         R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
@@ -873,27 +829,30 @@ impl PublicKey {
     ///   set, this will default to an empty string.
     /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// # Returns
     ///
     /// Returns `true` if the `signature` was a valid signature created by this
     /// `Keypair` on the `prehashed_message`.
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     #[allow(non_snake_case)]
-    pub fn verify_prehashed<D>(&self,
-                               prehashed_message: D,
-                               context: Option<&[u8]>,
-                               signature: &Signature) -> Result<(), SignatureError>
-        where D: Digest<OutputSize = U64> + Default
+    pub fn verify_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&[u8]>,
+        signature: &Signature,
+    ) -> Result<(), SignatureError>
+        where
+            D: Digest<OutputSize = U64>,
     {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::default();
         let R: EdwardsPoint;
         let k: Scalar;

         let ctx: &[u8] = context.unwrap_or(b"");
         debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");

         let minus_A: EdwardsPoint = -self.1;

         h.input(b"SigEd25519 no Ed25519 collisions");
         h.input(&[1]); // Ed25519ph
@@ -939,48 +898,47 @@ impl From<ExpandedSecretKey> for PublicKey {
 ///
 /// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a
 ///   `SignatureError` containing a description of the internal error which
 ///   occured.
 ///
 /// # Examples
 ///
 /// ```
 /// extern crate ed25519_dalek;
 /// extern crate rand;
-/// extern crate sha2;
 ///
 /// use ed25519_dalek::verify_batch;
 /// use ed25519_dalek::Keypair;
 /// use ed25519_dalek::PublicKey;
 /// use ed25519_dalek::Signature;
 /// use rand::thread_rng;
 /// use rand::rngs::ThreadRng;
-/// use sha2::Sha512;
 ///
 /// # fn main() {
 /// let mut csprng: ThreadRng = thread_rng();
-/// let keypairs: Vec<Keypair> = (0..64).map(|_| Keypair::generate::<Sha512, _>(&mut csprng)).collect();
+/// let keypairs: Vec<Keypair> = (0..64).map(|_| Keypair::generate(&mut csprng)).collect();
 /// let msg: &[u8] = b"They're good dogs Brant";
 /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect();
-/// let signatures:  Vec<Signature> = keypairs.iter().map(|key| key.sign::<Sha512>(&msg)).collect();
+/// let signatures:  Vec<Signature> = keypairs.iter().map(|key| key.sign(&msg)).collect();
 /// let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect();
 ///
-/// let result = verify_batch::<Sha512>(&messages[..], &signatures[..], &public_keys[..]);
+/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]);
 /// assert!(result.is_ok());
 /// # }
 /// ```
 #[cfg(any(feature = "alloc", feature = "std"))]
 #[allow(non_snake_case)]
-pub fn verify_batch<D>(messages: &[&[u8]],
-                       signatures: &[Signature],
-                       public_keys: &[PublicKey]) -> Result<(), SignatureError>
-    where D: Digest<OutputSize = U64> + Default
+pub fn verify_batch(
+    messages: &[&[u8]],
+    signatures: &[Signature],
+    public_keys: &[PublicKey],
+) -> Result<(), SignatureError>
 {
     const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal.";
     assert!(signatures.len()  == messages.len(),    ASSERT_MESSAGE);
     assert!(signatures.len()  == public_keys.len(), ASSERT_MESSAGE);
     assert!(public_keys.len() == messages.len(),    ASSERT_MESSAGE);

     #[cfg(feature = "alloc")]
     use alloc::vec::Vec;
     #[cfg(feature = "std")]
     use std::vec::Vec;
@@ -1000,21 +958,21 @@ pub fn verify_batch<D>(messages: &[&[u8]],
     // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l)
     let B_coefficient: Scalar = signatures
         .iter()
         .map(|sig| sig.s)
         .zip(zs.iter())
         .map(|(s, z)| z * s)
         .sum();

     // Compute H(R || A || M) for each (signature, public_key, message) triplet
     let hrams = (0..signatures.len()).map(|i| {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::default();
         h.input(signatures[i].R.as_bytes());
         h.input(public_keys[i].as_bytes());
         h.input(&messages[i]);
         Scalar::from_hash(h)
     });

     // Multiply each H(R || A || M) by the random value
     let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z);

     let Rs = signatures.iter().map(|sig| sig.R.decompress());
@@ -1118,64 +1076,63 @@ impl Keypair {

         Ok(Keypair{ secret: secret, public: public })
     }

     /// Generate an ed25519 keypair.
     ///
     /// # Example
     ///
     /// ```
     /// extern crate rand;
-    /// extern crate sha2;
     /// extern crate ed25519_dalek;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     ///
     /// use rand::Rng;
     /// use rand::OsRng;
-    /// use sha2::Sha512;
     /// use ed25519_dalek::Keypair;
     /// use ed25519_dalek::Signature;
     ///
     /// let mut csprng: OsRng = OsRng::new().unwrap();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     ///
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// # Input
     ///
     /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`.
     ///
     /// The caller must also supply a hash function which implements the
     /// `Digest` and `Default` traits, and which returns 512 bits of output.
     /// The standard hash function used for most ed25519 libraries is SHA-512,
     /// which is available with `use sha2::Sha512` as in the example above.
     /// Other suitable hash functions include Keccak-512 and Blake2b-512.
-    pub fn generate<D, R>(csprng: &mut R) -> Keypair
-        where D: Digest<OutputSize = U64> + Default,
-              R: CryptoRng + Rng,
+    pub fn generate<R>(csprng: &mut R) -> Keypair
+        where R: CryptoRng + Rng,
     {
         let sk: SecretKey = SecretKey::generate(csprng);
-        let pk: PublicKey = PublicKey::from_secret::<D>(&sk);
+        let pk: PublicKey = (&sk).into();

         Keypair{ public: pk, secret: sk }
     }

     /// Sign a message with this keypair's secret key.
-    pub fn sign<D>(&self, message: &[u8]) -> Signature
-            where D: Digest<OutputSize = U64> + Default {
-        self.secret.expand::<D>().sign::<D>(&message, &self.public)
+    pub fn sign(&self, message: &[u8]) -> Signature
+    {
+        let expanded: ExpandedSecretKey = (&self.secret).into();
+
+        expanded.sign(&message, &self.public)
     }

     /// Sign a `prehashed_message` with this `Keypair` using the
     /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032].
     ///
     /// # Inputs
     ///
     /// * `prehashed_message` is an instantiated hash digest with 512-bits of
     ///   output which has had the message to be signed previously fed into its
     ///   state.
@@ -1185,41 +1142,40 @@ impl Keypair {
     ///
     /// # Returns
     ///
     /// An Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// # Examples
     ///
     /// ```
     /// extern crate ed25519_dalek;
     /// extern crate rand;
-    /// extern crate sha2;
     ///
+    /// use ed25519_dalek::Digest;
     /// use ed25519_dalek::Keypair;
+    /// use ed25519_dalek::Sha512;
     /// use ed25519_dalek::Signature;
     /// use rand::thread_rng;
-    /// use sha2::Digest;
-    /// use sha2::Sha512;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// let mut csprng = thread_rng();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     /// let message: &[u8] = b"All I want is to pet all of the dogs.";
     ///
     /// // Create a hash digest object which we'll feed the message into:
-    /// let mut prehashed: Sha512 = Sha512::default();
+    /// let mut prehashed: Sha512 = Sha512::new();
     ///
     /// prehashed.input(message);
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// If you want, you can optionally pass a "context".  It is generally a
     /// good idea to choose a context and try to make it unique to your project
     /// and this specific usage of signatures.
     ///
     /// For example, without this, if you were to [convert your OpenPGP key
     /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't
     /// Ever Do That) and someone tricked you into signing an "email" which was
@@ -1233,59 +1189,67 @@ impl Keypair {
     /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol",
     /// then the signatures produced by both could never match the other, even
     /// if they signed the exact same message with the same key.
     ///
     /// Let's add a context for good measure (remember, you'll want to choose
     /// your own!):
     ///
     /// ```
     /// # extern crate ed25519_dalek;
     /// # extern crate rand;
-    /// # extern crate sha2;
     /// #
+    /// # use ed25519_dalek::Digest;
     /// # use ed25519_dalek::Keypair;
     /// # use ed25519_dalek::Signature;
+    /// # use ed25519_dalek::Sha512;
     /// # use rand::thread_rng;
-    /// # use sha2::Digest;
-    /// # use sha2::Sha512;
     /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// # let mut csprng = thread_rng();
-    /// # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// # let keypair: Keypair = Keypair::generate(&mut csprng);
     /// # let message: &[u8] = b"All I want is to pet all of the dogs.";
-    /// # let mut prehashed: Sha512 = Sha512::default();
+    /// # let mut prehashed: Sha512 = Sha512::new();
     /// # prehashed.input(message);
     /// #
     /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
     ///
     /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context));
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py
-    pub fn sign_prehashed<D>(&self,
-                             prehashed_message: D,
-                             context: Option<&'static [u8]>) -> Signature
-        where D: Digest<OutputSize = U64> + Default
+    pub fn sign_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&'static [u8]>
+    ) -> Signature
+        where
+            D: Digest<OutputSize = U64>,
     {
-        self.secret.expand::<D>().sign_prehashed::<D>(prehashed_message, &self.public, context)
+        let expanded: ExpandedSecretKey = (&self.secret).into();  // xxx thanks i hate this
+
+        expanded.sign_prehashed(prehashed_message, &self.public, context)
     }

     /// Verify a signature on a message with this keypair's public key.
-    pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError>
-            where D: Digest<OutputSize = U64> + Default {
-        self.public.verify::<D>(message, signature)
+    pub fn verify(
+        &self,
+        message: &[u8],
+        signature: &Signature
+    ) -> Result<(), SignatureError>
+    {
+        self.public.verify(message, signature)
     }

     /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm.
     ///
     /// # Inputs
     ///
     /// * `prehashed_message` is an instantiated hash digest with 512-bits of
     ///   output which has had the message to be signed previously fed into its
     ///   state.
     /// * `context` is an optional context string, up to 255 bytes inclusive,
@@ -1296,62 +1260,64 @@ impl Keypair {
     /// # Returns
     ///
     /// Returns `true` if the `signature` was a valid signature created by this
     /// `Keypair` on the `prehashed_message`.
     ///
     /// # Examples
     ///
     /// ```
     /// extern crate ed25519_dalek;
     /// extern crate rand;
-    /// extern crate sha2;
     ///
+    /// use ed25519_dalek::Digest;
     /// use ed25519_dalek::Keypair;
     /// use ed25519_dalek::Signature;
+    /// use ed25519_dalek::Sha512;
     /// use rand::thread_rng;
-    /// use sha2::Digest;
-    /// use sha2::Sha512;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// let mut csprng = thread_rng();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     /// let message: &[u8] = b"All I want is to pet all of the dogs.";
     ///
     /// let mut prehashed: Sha512 = Sha512::default();
     /// prehashed.input(message);
     ///
     /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
     ///
     /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context));
     ///
     /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one:
     /// let mut prehashed_again: Sha512 = Sha512::default();
     /// prehashed_again.input(message);
     ///
     /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig);
     ///
     /// assert!(verified.is_ok());
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
-    pub fn verify_prehashed<D>(&self,
-                               prehashed_message: D,
-                               context: Option<&[u8]>,
-                               signature: &Signature) -> Result<(), SignatureError>
-        where D: Digest<OutputSize = U64> + Default
+    pub fn verify_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&[u8]>,
+        signature: &Signature
+    ) -> Result<(), SignatureError>
+        where
+            D: Digest<OutputSize = U64>,
     {
-        self.public.verify_prehashed::<D>(prehashed_message, context, signature)
+        self.public.verify_prehashed(prehashed_message, context, signature)
     }
 }

 #[cfg(feature = "serde")]
 impl Serialize for Keypair {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
         serializer.serialize_bytes(&self.to_bytes()[..])
     }
 }

@@ -1428,29 +1394,29 @@ mod test {
     fn sign_verify() {  // TestSignVerify
         let mut csprng: ThreadRng;
         let keypair: Keypair;
         let good_sig: Signature;
         let bad_sig:  Signature;

         let good: &[u8] = "test message".as_bytes();
         let bad:  &[u8] = "wrong message".as_bytes();

         csprng  = thread_rng();
-        keypair  = Keypair::generate::<Sha512, _>(&mut csprng);
-        good_sig = keypair.sign::<Sha512>(&good);
-        bad_sig  = keypair.sign::<Sha512>(&bad);
+        keypair  = Keypair::generate(&mut csprng);
+        good_sig = keypair.sign(&good);
+        bad_sig  = keypair.sign(&bad);

-        assert!(keypair.verify::<Sha512>(&good, &good_sig).is_ok(),
+        assert!(keypair.verify(&good, &good_sig).is_ok(),
                 "Verification of a valid signature failed!");
-        assert!(keypair.verify::<Sha512>(&good, &bad_sig).is_err(),
+        assert!(keypair.verify(&good, &bad_sig).is_err(),
                 "Verification of a signature on a different message passed!");
-        assert!(keypair.verify::<Sha512>(&bad,  &good_sig).is_err(),
+        assert!(keypair.verify(&bad,  &good_sig).is_err(),
                 "Verification of a signature on a different message passed!");
     }

     // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang
     // package. It is a selection of test cases from
     // http://ed25519.cr.yp.to/python/sign.input
     #[cfg(test)]
     #[cfg(not(release))]
     #[test]
     fn golden() { // TestGolden
@@ -1478,24 +1444,24 @@ mod test {
             let msg_bytes: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap();
             let sig_bytes: Vec<u8> = FromHex::from_hex(&parts[3]).unwrap();

             let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap();
             let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap();
             let keypair: Keypair  = Keypair{ secret: secret, public: public };

 		    // The signatures in the test vectors also include the message
 		    // at the end, but we just want R and S.
             let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap();
-            let sig2: Signature = keypair.sign::<Sha512>(&msg_bytes);
+            let sig2: Signature = keypair.sign(&msg_bytes);

             assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno);
-            assert!(keypair.verify::<Sha512>(&msg_bytes, &sig2).is_ok(),
+            assert!(keypair.verify(&msg_bytes, &sig2).is_ok(),
                     "Signature verification failed on line {}", lineno);
         }
     }

     // From https://tools.ietf.org/html/rfc8032#section-7.3
     #[test]
     fn ed25519ph_rf8032_test_vector() {
         let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42";
         let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf";
         let message: &[u8] = b"616263";
@@ -1545,54 +1511,54 @@ mod test {
         prehashed_good3.input(good);

         let mut prehashed_bad1: Sha512 = Sha512::default();
         prehashed_bad1.input(bad);
         let mut prehashed_bad2: Sha512 = Sha512::default();
         prehashed_bad2.input(bad);

         let context: &[u8] = b"testing testing 1 2 3";

         csprng   = thread_rng();
-        keypair  = Keypair::generate::<Sha512, _>(&mut csprng);
-        good_sig = keypair.sign_prehashed::<Sha512>(prehashed_good1, Some(context));
-        bad_sig  = keypair.sign_prehashed::<Sha512>(prehashed_bad1,  Some(context));
+        keypair  = Keypair::generate(&mut csprng);
+        good_sig = keypair.sign_prehashed(prehashed_good1, Some(context));
+        bad_sig  = keypair.sign_prehashed(prehashed_bad1,  Some(context));

-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_good2, Some(context), &good_sig).is_ok(),
+        assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(),
                 "Verification of a valid signature failed!");
-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_good3, Some(context), &bad_sig).is_err(),
+        assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(),
                 "Verification of a signature on a different message passed!");
-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_bad2,  Some(context), &good_sig).is_err(),
+        assert!(keypair.verify_prehashed(prehashed_bad2,  Some(context), &good_sig).is_err(),
                 "Verification of a signature on a different message passed!");
     }

     #[test]
     fn verify_batch_seven_signatures() {
         let messages: [&[u8]; 7] = [
             b"Watch closely everyone, I'm going to show you how to kill a god.",
             b"I'm not a cryptographer I just encrypt a lot.",
             b"Still not a cryptographer.",
             b"This is a test of the tsunami alert system. This is only a test.",
             b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.",
             b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.",
             b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ];
         let mut csprng: ThreadRng = thread_rng();
         let mut keypairs: Vec<Keypair> = Vec::new();
         let mut signatures: Vec<Signature> = Vec::new();

         for i in 0..messages.len() {
-            let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-            signatures.push(keypair.sign::<Sha512>(&messages[i]));
+            let keypair: Keypair = Keypair::generate(&mut csprng);
+            signatures.push(keypair.sign(&messages[i]));
             keypairs.push(keypair);
         }
         let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect();

-        let result = verify_batch::<Sha512>(&messages, &signatures[..], &public_keys[..]);
+        let result = verify_batch(&messages, &signatures[..], &public_keys[..]);

         assert!(result.is_ok());
     }

     #[test]
     fn public_key_from_bytes() {
         // Make another function so that we can test the ? operator.
         fn do_the_test() -> Result<PublicKey, SignatureError> {
             let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
                 215, 090, 152, 001, 130, 177, 010, 183,
@@ -1629,24 +1595,24 @@ mod test {
                 slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x))
             }
         }

         assert!(!as_bytes(&keypair).contains(&0x15));
     }

     #[test]
     fn pubkey_from_secret_and_expanded_secret() {
         let mut csprng = thread_rng();
-        let secret: SecretKey = SecretKey::generate::<_>(&mut csprng);
-        let expanded_secret: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::<Sha512>(&secret);
-        let public_from_secret: PublicKey = PublicKey::from_secret::<Sha512>(&secret);
-        let public_from_expanded_secret: PublicKey = PublicKey::from_expanded_secret(&expanded_secret);
+        let secret: SecretKey = SecretKey::generate(&mut csprng);
+        let expanded_secret: ExpandedSecretKey = (&secret).into();
+        let public_from_secret: PublicKey = (&secret).into(); // XXX eww
+        let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww

         assert!(public_from_secret == public_from_expanded_secret);
     }

     #[cfg(all(test, feature = "serde"))]
     use bincode::{serialize, serialized_size, deserialize, Infinite};

     #[cfg(all(test, feature = "serde"))]
     #[test]
     fn serialize_deserialize_signature() {
diff --git c/src/lib.rs i/src/lib.rs
index ff8ed03..b0854ba 100644
--- c/src/lib.rs
+++ i/src/lib.rs
@@ -8,156 +8,143 @@
 // - Isis Agora Lovecruft <isis@patternsinthevoid.net>

 //! ed25519 signatures and verification
 //!
 //! # Example
 //!
 //! Creating an ed25519 signature on a message is simple.
 //!
 //! First, we need to generate a `Keypair`, which includes both public and
 //! secret halves of an asymmetric key.  To do so, we need a cryptographically
-//! secure pseudorandom number generator (CSPRNG), and a hash function which
-//! has 512 bits of output.  For this example, we'll use the operating
-//! system's builtin PRNG and SHA-512 to generate a keypair:
+//! secure pseudorandom number generator (CSPRNG). For this example, we'll use
+//! the operating system's builtin PRNG:
 //!
 //! ```
 //! extern crate rand;
-//! extern crate sha2;
 //! extern crate ed25519_dalek;
 //!
-//! # #[cfg(all(feature = "std", feature = "sha2"))]
+//! # #[cfg(feature = "std")]
 //! # fn main() {
 //! use rand::Rng;
 //! use rand::OsRng;
-//! use sha2::Sha512;
 //! use ed25519_dalek::Keypair;
 //! use ed25519_dalek::Signature;
 //!
 //! let mut csprng: OsRng = OsRng::new().unwrap();
-//! let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); // The `_` can be the type of `csprng`
+//! let keypair: Keypair = Keypair::generate(&mut csprng);
 //! # }
 //! #
-//! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))]
+//! # #[cfg(not(feature = "std"))]
 //! # fn main() { }
 //! ```
 //!
 //! We can now use this `keypair` to sign a message:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! let signature: Signature = keypair.sign(message);
 //! # }
 //! ```
 //!
 //! As well as to verify that this is, indeed, a valid signature on
 //! that `message`:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
-//! assert!(keypair.verify::<Sha512>(message, &signature).is_ok());
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
+//! assert!(keypair.verify(message, &signature).is_ok());
 //! # }
 //! ```
 //!
 //! Anyone else, given the `public` half of the `keypair` can also easily
 //! verify this signature:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! use ed25519_dalek::PublicKey;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //!
 //! let public_key: PublicKey = keypair.public;
-//! assert!(public_key.verify::<Sha512>(message, &signature).is_ok());
+//! assert!(public_key.verify(message, &signature).is_ok());
 //! # }
 //! ```
 //!
 //! ## Serialisation
 //!
 //! `PublicKey`s, `SecretKey`s, `Keypair`s, and `Signature`s can be serialised
 //! into byte-arrays by calling `.to_bytes()`.  It's perfectly acceptible and
 //! safe to transfer and/or store those bytes.  (Of course, never transfer your
 //! secret key to anyone else, since they will only need the public key to
 //! verify your signatures!)
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
 //!
 //! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes();
 //! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes();
 //! let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair.to_bytes();
 //! let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature.to_bytes();
 //! # }
 //! ```
 //!
 //! And similarly, decoded from bytes with `::from_bytes()`:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError};
 //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
 //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> {
 //! # let mut csprng = thread_rng();
-//! # let keypair_orig: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature_orig: Signature = keypair_orig.sign::<Sha512>(message);
+//! # let keypair_orig: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature_orig: Signature = keypair_orig.sign(message);
 //! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes();
 //! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes();
 //! # let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair_orig.to_bytes();
 //! # let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature_orig.to_bytes();
 //! #
 //! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?;
 //! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?;
 //! let keypair:    Keypair   = Keypair::from_bytes(&keypair_bytes)?;
 //! let signature:  Signature = Signature::from_bytes(&signature_bytes)?;
 //! #
@@ -176,84 +163,80 @@
 //!
 //! ```bash
 //! $ cargo build --features="serde"
 //! ```
 //!
 //! They can be then serialised into any of the wire formats which serde supports.
 //! For example, using [bincode](https://github.com/TyOverby/bincode):
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # #[cfg(feature = "serde")]
 //! extern crate serde;
 //! # #[cfg(feature = "serde")]
 //! extern crate bincode;
 //!
 //! # #[cfg(feature = "serde")]
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! use bincode::{serialize, Infinite};
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
-//! # let verified: bool = public_key.verify::<Sha512>(message, &signature).is_ok();
+//! # let verified: bool = public_key.verify(message, &signature).is_ok();
 //!
 //! let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
 //! let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
 //! # }
 //! # #[cfg(not(feature = "serde"))]
 //! # fn main() {}
 //! ```
 //!
 //! After sending the `encoded_public_key` and `encoded_signature`, the
 //! recipient may deserialise them and verify:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # #[cfg(feature = "serde")]
 //! # extern crate serde;
 //! # #[cfg(feature = "serde")]
 //! # extern crate bincode;
 //! #
 //! # #[cfg(feature = "serde")]
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! # use bincode::{serialize, Infinite};
 //! use bincode::{deserialize};
 //!
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
-//! # let verified: bool = public_key.verify::<Sha512>(message, &signature).is_ok();
+//! # let verified: bool = public_key.verify(message, &signature).is_ok();
 //! # let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
 //! # let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
 //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
 //! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
 //!
 //! # assert_eq!(public_key, decoded_public_key);
 //! # assert_eq!(signature, decoded_signature);
 //! #
-//! let verified: bool = decoded_public_key.verify::<Sha512>(&message, &decoded_signature).is_ok();
+//! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok();
 //!
 //! assert!(verified);
 //! # }
 //! # #[cfg(not(feature = "serde"))]
 //! # fn main() {}
 //! ```

 #![no_std]
 #![allow(unused_features)]
 #![deny(missing_docs)] // refuse to compile if documentation is missing
isislovecruft added a commit to isislovecruft/ed25519-dalek that referenced this issue Dec 29, 2018
This implements dalek-cryptography#64

You can still choose the "prehash" algorithm, as long as it has 64 bytes of
output.  Otherwise, everything is hardcoded to use sha2::Sha512.  To use a
different implementation you'll need a [patch.crates-io] section in cargo
config.

diff --git c/Cargo.toml i/Cargo.toml
index 5b04835..5d5cc94 100644
--- c/Cargo.toml
+++ i/Cargo.toml
@@ -22,40 +22,39 @@ default-features = false
 [dependencies.rand]
 version = "0.6"
 features = ["i128_support"]

 [dependencies.serde]
 version = "^1.0"
 optional = true

 [dependencies.sha2]
 version = "^0.8"
-optional = true
+default-features = false

 [dependencies.failure]
 version = "^0.1.1"
 default-features = false

 [dependencies.clear_on_drop]
 version = "0.2"

 [dev-dependencies]
 hex = "^0.3"
-sha2 = "^0.8"
 bincode = "^0.9"
 criterion = "0.2"

 [[bench]]
 name = "ed25519_benchmarks"
 harness = false

 [features]
 default = ["std", "u64_backend"]
 # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies.
-std = ["curve25519-dalek/std", "rand/std"]
+std = ["curve25519-dalek/std", "rand/std", "sha2/std"]
 alloc = ["curve25519-dalek/alloc"]
 nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"]
 asm = ["sha2/asm"]
 yolocrypto = ["curve25519-dalek/yolocrypto"]
 u64_backend = ["curve25519-dalek/u64_backend"]
 u32_backend = ["curve25519-dalek/u32_backend"]
 avx2_backend = ["curve25519-dalek/avx2_backend"]
diff --git c/src/ed25519.rs i/src/ed25519.rs
index 4d2fabd..c7f5c69 100644
--- c/src/ed25519.rs
+++ i/src/ed25519.rs
@@ -1,43 +1,41 @@
 // -*- mode: rust; -*-
 //
 // This file is part of ed25519-dalek.
 // Copyright (c) 2017-2018 Isis Lovecruft
 // See LICENSE for licensing information.
 //
 // Authors:
 // - Isis Agora Lovecruft <isis@patternsinthevoid.net>

-//! A Rust implementation of ed25519 EdDSA key generation, signing, and
-//! verification.
+//! A Rust implementation of ed25519 key generation, signing, and verification.

 use core::default::Default;
 use core::fmt::{Debug};

 use rand::CryptoRng;
 use rand::Rng;

 #[cfg(feature = "serde")]
 use serde::{Serialize, Deserialize};
 #[cfg(feature = "serde")]
 use serde::{Serializer, Deserializer};
 #[cfg(feature = "serde")]
 use serde::de::Error as SerdeError;
 #[cfg(feature = "serde")]
 use serde::de::Visitor;

-#[cfg(feature = "sha2")]
-use sha2::Sha512;
+pub use sha2::Sha512;

 use clear_on_drop::clear::Clear;

-use curve25519_dalek::digest::Digest;
+pub use curve25519_dalek::digest::Digest;
 use curve25519_dalek::digest::generic_array::typenum::U64;

 use curve25519_dalek::constants;
 use curve25519_dalek::edwards::CompressedEdwardsY;
 use curve25519_dalek::edwards::EdwardsPoint;
 use curve25519_dalek::scalar::Scalar;

 use errors::SignatureError;
 use errors::InternalError;

@@ -181,27 +179,20 @@ impl Drop for SecretKey {
     }
 }

 impl AsRef<[u8]> for SecretKey {
     fn as_ref(&self) -> &[u8] {
         self.as_bytes()
     }
 }

 impl SecretKey {
-    /// Expand this `SecretKey` into an `ExpandedSecretKey`.
-    pub fn expand<D>(&self) -> ExpandedSecretKey
-        where D: Digest<OutputSize = U64> + Default
-    {
-        ExpandedSecretKey::from_secret_key::<D>(&self)
-    }
-
     /// Convert this secret key to a byte array.
     #[inline]
     pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
         self.0
     }

     /// View this secret key as a byte array.
     #[inline]
     pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] {
         &self.0
@@ -272,52 +263,44 @@ impl SecretKey {
     /// use ed25519_dalek::Signature;
     ///
     /// let mut csprng: OsRng = OsRng::new().unwrap();
     /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     /// # }
     /// #
     /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
-    /// Afterwards, you can generate the corresponding public—provided you also
-    /// supply a hash function which implements the `Digest` and `Default`
-    /// traits, and which returns 512 bits of output—via:
+    /// Afterwards, you can generate the corresponding public:
     ///
     /// ```
     /// # extern crate rand;
-    /// # extern crate sha2;
     /// # extern crate ed25519_dalek;
     /// #
     /// # fn main() {
     /// #
     /// # use rand::Rng;
     /// # use rand::thread_rng;
-    /// # use sha2::Sha512;
     /// # use ed25519_dalek::PublicKey;
     /// # use ed25519_dalek::SecretKey;
     /// # use ed25519_dalek::Signature;
     /// #
     /// # let mut csprng = thread_rng();
     /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     ///
-    /// let public_key: PublicKey = PublicKey::from_secret::<Sha512>(&secret_key);
+    /// let public_key: PublicKey = (&secret_key).into();
     /// # }
     /// ```
     ///
-    /// The standard hash function used for most ed25519 libraries is SHA-512,
-    /// which is available with `use sha2::Sha512` as in the example above.
-    /// Other suitable hash functions include Keccak-512 and Blake2b-512.
-    ///
     /// # Input
     ///
-    /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`
+    /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng`
     pub fn generate<T>(csprng: &mut T) -> SecretKey
         where T: CryptoRng + Rng,
     {
         let mut sk: SecretKey = SecretKey([0u8; 32]);

         csprng.fill_bytes(&mut sk.0);

         sk
     }
 }
@@ -391,49 +374,59 @@ pub struct ExpandedSecretKey {
 }

 /// Overwrite secret key material with null bytes when it goes out of scope.
 impl Drop for ExpandedSecretKey {
     fn drop(&mut self) {
         self.key.clear();
         self.nonce.clear();
     }
 }

-#[cfg(feature = "sha2")]
 impl<'a> From<&'a SecretKey> for ExpandedSecretKey {
     /// Construct an `ExpandedSecretKey` from a `SecretKey`.
     ///
     /// # Examples
     ///
     /// ```
     /// # extern crate rand;
     /// # extern crate sha2;
     /// # extern crate ed25519_dalek;
     /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
     /// # fn main() {
     /// #
     /// use rand::Rng;
-    /// use rand::rngs::OsRng;
+    /// use rand::thread_rng;
     /// use sha2::Sha512;
     /// use ed25519_dalek::{SecretKey, ExpandedSecretKey};
     ///
-    /// let mut csprng: OsRng = OsRng::new().unwrap();
+    /// let mut csprng = thread_rng();
     /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key);
     /// # }
-    /// #
-    /// # #[cfg(any(not(feature = "std"), not(feature = "sha2")))]
-    /// # fn main() {}
     /// ```
     fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey {
-        ExpandedSecretKey::from_secret_key::<Sha512>(&secret_key)
+        let mut h: Sha512 = Sha512::default();
+        let mut hash:  [u8; 64] = [0u8; 64];
+        let mut lower: [u8; 32] = [0u8; 32];
+        let mut upper: [u8; 32] = [0u8; 32];
+
+        h.input(secret_key.as_bytes());
+        hash.copy_from_slice(h.result().as_slice());
+
+        lower.copy_from_slice(&hash[00..32]);
+        upper.copy_from_slice(&hash[32..64]);
+
+        lower[0]  &= 248;
+        lower[31] &=  63;
+        lower[31] |=  64;
+
+        ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, }
     }
 }

 impl ExpandedSecretKey {
     /// Convert this `ExpandedSecretKey` into an array of 64 bytes.
     ///
     /// # Returns
     ///
     /// An array of 64 bytes.  The first 32 bytes represent the "expanded"
     /// secret key, and the last 32 bytes represent the "domain-separation"
@@ -525,82 +518,36 @@ impl ExpandedSecretKey {
         let mut lower: [u8; 32] = [0u8; 32];
         let mut upper: [u8; 32] = [0u8; 32];

         lower.copy_from_slice(&bytes[00..32]);
         upper.copy_from_slice(&bytes[32..64]);

         Ok(ExpandedSecretKey{ key:   Scalar::from_bits(lower),
                               nonce:                   upper  })
     }

-    /// Construct an `ExpandedSecretKey` from a `SecretKey`, using hash function `D`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # extern crate rand;
-    /// # extern crate sha2;
-    /// # extern crate ed25519_dalek;
-    /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
-    /// # fn main() {
-    /// #
-    /// use rand::Rng;
-    /// use rand::rngs::OsRng;
-    /// use sha2::Sha512;
-    /// use ed25519_dalek::{SecretKey, ExpandedSecretKey};
-    ///
-    /// let mut csprng: OsRng = OsRng::new().unwrap();
-    /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
-    /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::<Sha512>(&secret_key);
-    /// # }
-    /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
-    /// # fn main() { }
-    /// ```
-    pub fn from_secret_key<D>(secret_key: &SecretKey) -> ExpandedSecretKey
-            where D: Digest<OutputSize = U64> + Default {
-        let mut h: D = D::default();
-        let mut hash:  [u8; 64] = [0u8; 64];
-        let mut lower: [u8; 32] = [0u8; 32];
-        let mut upper: [u8; 32] = [0u8; 32];
-
-        h.input(secret_key.as_bytes());
-        hash.copy_from_slice(h.result().as_slice());
-
-        lower.copy_from_slice(&hash[00..32]);
-        upper.copy_from_slice(&hash[32..64]);
-
-        lower[0]  &= 248;
-        lower[31] &=  63;
-        lower[31] |=  64;
-
-        ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, }
-    }
-
     /// Sign a message with this `ExpandedSecretKey`.
     #[allow(non_snake_case)]
-    pub fn sign<D>(&self, message: &[u8], public_key: &PublicKey) -> Signature
-            where D: Digest<OutputSize = U64> + Default {
-        let mut h: D = D::default();
+    pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature {
+        let mut h: Sha512 = Sha512::new();
         let R: CompressedEdwardsY;
         let r: Scalar;
         let s: Scalar;
         let k: Scalar;

         h.input(&self.nonce);
         h.input(&message);

         r = Scalar::from_hash(h);
         R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();

-        h = D::default();
+        h = Sha512::new();
         h.input(R.as_bytes());
         h.input(public_key.as_bytes());
         h.input(&message);

         k = Scalar::from_hash(h);
         s = &(&k * &self.key) + &r;

         Signature{ R, s }
     }

@@ -616,27 +563,30 @@ impl ExpandedSecretKey {
     /// * `context` is an optional context string, up to 255 bytes inclusive,
     ///   which may be used to provide additional domain separation.  If not
     ///   set, this will default to an empty string.
     ///
     /// # Returns
     ///
     /// An Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     #[allow(non_snake_case)]
-    pub fn sign_prehashed<D>(&self,
-                             prehashed_message: D,
-                             public_key: &PublicKey,
-                             context: Option<&'static [u8]>) -> Signature
-        where D: Digest<OutputSize = U64> + Default
+    pub fn sign_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        public_key: &PublicKey,
+        context: Option<&'static [u8]>,
+    ) -> Signature
+        where
+            D: Digest<OutputSize = U64>,
     {
-        let mut h: D;
+        let mut h: Sha512;
         let mut prehash: [u8; 64] = [0u8; 64];
         let R: CompressedEdwardsY;
         let r: Scalar;
         let s: Scalar;
         let k: Scalar;

         let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string.

         debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");

@@ -650,32 +600,32 @@ impl ExpandedSecretKey {
         // the upper half "prefix" of the hashed "secret key" in here?  Why
         // can't the user just supply their own nonce and decide for themselves
         // whether or not they want a deterministic signature scheme?  Why does
         // the message go into what's ostensibly the signature domain separation
         // hash?  Why wasn't there always a way to provide a context string?
         //
         // ...
         //
         // This is a really fucking stupid bandaid, and the damned scheme is
         // still bleeding from malleability, for fuck's sake.
-        h = D::default()
+        h = Sha512::new()
             .chain(b"SigEd25519 no Ed25519 collisions")
             .chain(&[1]) // Ed25519ph
             .chain(&[ctx_len])
             .chain(ctx)
             .chain(&self.nonce)
             .chain(&prehash[..]);

         r = Scalar::from_hash(h);
         R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();

-        h = D::default()
+        h = Sha512::new()
             .chain(b"SigEd25519 no Ed25519 collisions")
             .chain(&[1]) // Ed25519ph
             .chain(&[ctx_len])
             .chain(ctx)
             .chain(R.as_bytes())
             .chain(public_key.as_bytes())
             .chain(&prehash[..]);

         k = Scalar::from_hash(h);
         s = &(&k * &self.key) + &r;
@@ -787,69 +737,75 @@ impl PublicKey {
                 name: "PublicKey", length: PUBLIC_KEY_LENGTH }));
         }
         let mut bits: [u8; 32] = [0u8; 32];
         bits.copy_from_slice(&bytes[..32]);

         let compressed = CompressedEdwardsY(bits);
         let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?;

         Ok(PublicKey(compressed, point))
     }
+}

+impl<'a> From<&'a SecretKey> for PublicKey {
     /// Derive this public key from its corresponding `SecretKey`.
-    #[allow(unused_assignments)]
-    pub fn from_secret<D>(secret_key: &SecretKey) -> PublicKey
-        where D: Digest<OutputSize = U64> + Default
-    {
-        let mut h:    D = D::default();
+    fn from(secret_key: &SecretKey) -> PublicKey {
+        let mut h:    Sha512 = Sha512::new();
         let mut hash:   [u8; 64] = [0u8; 64];
         let mut digest: [u8; 32] = [0u8; 32];

         h.input(secret_key.as_bytes());
         hash.copy_from_slice(h.result().as_slice());

         digest.copy_from_slice(&hash[..32]);

         PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest)
     }
+}

+impl<'a> From<&'a ExpandedSecretKey> for PublicKey {
     /// Derive this public key from its corresponding `ExpandedSecretKey`.
-    pub fn from_expanded_secret(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
+    fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
         let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes();

         PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits)
     }
+}

+impl PublicKey {
     /// Internal utility function for mangling the bits of a (formerly
     /// mathematically well-defined) "scalar" and multiplying it to produce a
     /// public key.
     fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey {
         bits[0]  &= 248;
         bits[31] &= 127;
         bits[31] |= 64;

         let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE;
         let compressed = point.compress();

         PublicKey(compressed, point)
     }

     /// Verify a signature on a message with this keypair's public key.
     ///
     /// # Return
     ///
     /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
     #[allow(non_snake_case)]
-    pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError>
-            where D: Digest<OutputSize = U64> + Default
+    pub fn verify(
+        &self,
+        message: &[u8],
+        signature: &Signature
+    ) -> Result<(), SignatureError>
     {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::new();
         let R: EdwardsPoint;
         let k: Scalar;
         let minus_A: EdwardsPoint = -self.1;

         h.input(signature.R.as_bytes());
         h.input(self.as_bytes());
         h.input(&message);

         k = Scalar::from_hash(h);
         R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
@@ -873,27 +829,30 @@ impl PublicKey {
     ///   set, this will default to an empty string.
     /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// # Returns
     ///
     /// Returns `true` if the `signature` was a valid signature created by this
     /// `Keypair` on the `prehashed_message`.
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     #[allow(non_snake_case)]
-    pub fn verify_prehashed<D>(&self,
-                               prehashed_message: D,
-                               context: Option<&[u8]>,
-                               signature: &Signature) -> Result<(), SignatureError>
-        where D: Digest<OutputSize = U64> + Default
+    pub fn verify_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&[u8]>,
+        signature: &Signature,
+    ) -> Result<(), SignatureError>
+        where
+            D: Digest<OutputSize = U64>,
     {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::default();
         let R: EdwardsPoint;
         let k: Scalar;

         let ctx: &[u8] = context.unwrap_or(b"");
         debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");

         let minus_A: EdwardsPoint = -self.1;

         h.input(b"SigEd25519 no Ed25519 collisions");
         h.input(&[1]); // Ed25519ph
@@ -939,48 +898,47 @@ impl From<ExpandedSecretKey> for PublicKey {
 ///
 /// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a
 ///   `SignatureError` containing a description of the internal error which
 ///   occured.
 ///
 /// # Examples
 ///
 /// ```
 /// extern crate ed25519_dalek;
 /// extern crate rand;
-/// extern crate sha2;
 ///
 /// use ed25519_dalek::verify_batch;
 /// use ed25519_dalek::Keypair;
 /// use ed25519_dalek::PublicKey;
 /// use ed25519_dalek::Signature;
 /// use rand::thread_rng;
 /// use rand::rngs::ThreadRng;
-/// use sha2::Sha512;
 ///
 /// # fn main() {
 /// let mut csprng: ThreadRng = thread_rng();
-/// let keypairs: Vec<Keypair> = (0..64).map(|_| Keypair::generate::<Sha512, _>(&mut csprng)).collect();
+/// let keypairs: Vec<Keypair> = (0..64).map(|_| Keypair::generate(&mut csprng)).collect();
 /// let msg: &[u8] = b"They're good dogs Brant";
 /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect();
-/// let signatures:  Vec<Signature> = keypairs.iter().map(|key| key.sign::<Sha512>(&msg)).collect();
+/// let signatures:  Vec<Signature> = keypairs.iter().map(|key| key.sign(&msg)).collect();
 /// let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect();
 ///
-/// let result = verify_batch::<Sha512>(&messages[..], &signatures[..], &public_keys[..]);
+/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]);
 /// assert!(result.is_ok());
 /// # }
 /// ```
 #[cfg(any(feature = "alloc", feature = "std"))]
 #[allow(non_snake_case)]
-pub fn verify_batch<D>(messages: &[&[u8]],
-                       signatures: &[Signature],
-                       public_keys: &[PublicKey]) -> Result<(), SignatureError>
-    where D: Digest<OutputSize = U64> + Default
+pub fn verify_batch(
+    messages: &[&[u8]],
+    signatures: &[Signature],
+    public_keys: &[PublicKey],
+) -> Result<(), SignatureError>
 {
     const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal.";
     assert!(signatures.len()  == messages.len(),    ASSERT_MESSAGE);
     assert!(signatures.len()  == public_keys.len(), ASSERT_MESSAGE);
     assert!(public_keys.len() == messages.len(),    ASSERT_MESSAGE);

     #[cfg(feature = "alloc")]
     use alloc::vec::Vec;
     #[cfg(feature = "std")]
     use std::vec::Vec;
@@ -1000,21 +958,21 @@ pub fn verify_batch<D>(messages: &[&[u8]],
     // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l)
     let B_coefficient: Scalar = signatures
         .iter()
         .map(|sig| sig.s)
         .zip(zs.iter())
         .map(|(s, z)| z * s)
         .sum();

     // Compute H(R || A || M) for each (signature, public_key, message) triplet
     let hrams = (0..signatures.len()).map(|i| {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::default();
         h.input(signatures[i].R.as_bytes());
         h.input(public_keys[i].as_bytes());
         h.input(&messages[i]);
         Scalar::from_hash(h)
     });

     // Multiply each H(R || A || M) by the random value
     let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z);

     let Rs = signatures.iter().map(|sig| sig.R.decompress());
@@ -1118,64 +1076,63 @@ impl Keypair {

         Ok(Keypair{ secret: secret, public: public })
     }

     /// Generate an ed25519 keypair.
     ///
     /// # Example
     ///
     /// ```
     /// extern crate rand;
-    /// extern crate sha2;
     /// extern crate ed25519_dalek;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     ///
     /// use rand::Rng;
     /// use rand::OsRng;
-    /// use sha2::Sha512;
     /// use ed25519_dalek::Keypair;
     /// use ed25519_dalek::Signature;
     ///
     /// let mut csprng: OsRng = OsRng::new().unwrap();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     ///
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// # Input
     ///
     /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`.
     ///
     /// The caller must also supply a hash function which implements the
     /// `Digest` and `Default` traits, and which returns 512 bits of output.
     /// The standard hash function used for most ed25519 libraries is SHA-512,
     /// which is available with `use sha2::Sha512` as in the example above.
     /// Other suitable hash functions include Keccak-512 and Blake2b-512.
-    pub fn generate<D, R>(csprng: &mut R) -> Keypair
-        where D: Digest<OutputSize = U64> + Default,
-              R: CryptoRng + Rng,
+    pub fn generate<R>(csprng: &mut R) -> Keypair
+        where R: CryptoRng + Rng,
     {
         let sk: SecretKey = SecretKey::generate(csprng);
-        let pk: PublicKey = PublicKey::from_secret::<D>(&sk);
+        let pk: PublicKey = (&sk).into();

         Keypair{ public: pk, secret: sk }
     }

     /// Sign a message with this keypair's secret key.
-    pub fn sign<D>(&self, message: &[u8]) -> Signature
-            where D: Digest<OutputSize = U64> + Default {
-        self.secret.expand::<D>().sign::<D>(&message, &self.public)
+    pub fn sign(&self, message: &[u8]) -> Signature
+    {
+        let expanded: ExpandedSecretKey = (&self.secret).into();
+
+        expanded.sign(&message, &self.public)
     }

     /// Sign a `prehashed_message` with this `Keypair` using the
     /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032].
     ///
     /// # Inputs
     ///
     /// * `prehashed_message` is an instantiated hash digest with 512-bits of
     ///   output which has had the message to be signed previously fed into its
     ///   state.
@@ -1185,41 +1142,40 @@ impl Keypair {
     ///
     /// # Returns
     ///
     /// An Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// # Examples
     ///
     /// ```
     /// extern crate ed25519_dalek;
     /// extern crate rand;
-    /// extern crate sha2;
     ///
+    /// use ed25519_dalek::Digest;
     /// use ed25519_dalek::Keypair;
+    /// use ed25519_dalek::Sha512;
     /// use ed25519_dalek::Signature;
     /// use rand::thread_rng;
-    /// use sha2::Digest;
-    /// use sha2::Sha512;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// let mut csprng = thread_rng();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     /// let message: &[u8] = b"All I want is to pet all of the dogs.";
     ///
     /// // Create a hash digest object which we'll feed the message into:
-    /// let mut prehashed: Sha512 = Sha512::default();
+    /// let mut prehashed: Sha512 = Sha512::new();
     ///
     /// prehashed.input(message);
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// If you want, you can optionally pass a "context".  It is generally a
     /// good idea to choose a context and try to make it unique to your project
     /// and this specific usage of signatures.
     ///
     /// For example, without this, if you were to [convert your OpenPGP key
     /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't
     /// Ever Do That) and someone tricked you into signing an "email" which was
@@ -1233,59 +1189,67 @@ impl Keypair {
     /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol",
     /// then the signatures produced by both could never match the other, even
     /// if they signed the exact same message with the same key.
     ///
     /// Let's add a context for good measure (remember, you'll want to choose
     /// your own!):
     ///
     /// ```
     /// # extern crate ed25519_dalek;
     /// # extern crate rand;
-    /// # extern crate sha2;
     /// #
+    /// # use ed25519_dalek::Digest;
     /// # use ed25519_dalek::Keypair;
     /// # use ed25519_dalek::Signature;
+    /// # use ed25519_dalek::Sha512;
     /// # use rand::thread_rng;
-    /// # use sha2::Digest;
-    /// # use sha2::Sha512;
     /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// # let mut csprng = thread_rng();
-    /// # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// # let keypair: Keypair = Keypair::generate(&mut csprng);
     /// # let message: &[u8] = b"All I want is to pet all of the dogs.";
-    /// # let mut prehashed: Sha512 = Sha512::default();
+    /// # let mut prehashed: Sha512 = Sha512::new();
     /// # prehashed.input(message);
     /// #
     /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
     ///
     /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context));
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py
-    pub fn sign_prehashed<D>(&self,
-                             prehashed_message: D,
-                             context: Option<&'static [u8]>) -> Signature
-        where D: Digest<OutputSize = U64> + Default
+    pub fn sign_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&'static [u8]>
+    ) -> Signature
+        where
+            D: Digest<OutputSize = U64>,
     {
-        self.secret.expand::<D>().sign_prehashed::<D>(prehashed_message, &self.public, context)
+        let expanded: ExpandedSecretKey = (&self.secret).into();  // xxx thanks i hate this
+
+        expanded.sign_prehashed(prehashed_message, &self.public, context)
     }

     /// Verify a signature on a message with this keypair's public key.
-    pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError>
-            where D: Digest<OutputSize = U64> + Default {
-        self.public.verify::<D>(message, signature)
+    pub fn verify(
+        &self,
+        message: &[u8],
+        signature: &Signature
+    ) -> Result<(), SignatureError>
+    {
+        self.public.verify(message, signature)
     }

     /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm.
     ///
     /// # Inputs
     ///
     /// * `prehashed_message` is an instantiated hash digest with 512-bits of
     ///   output which has had the message to be signed previously fed into its
     ///   state.
     /// * `context` is an optional context string, up to 255 bytes inclusive,
@@ -1296,62 +1260,64 @@ impl Keypair {
     /// # Returns
     ///
     /// Returns `true` if the `signature` was a valid signature created by this
     /// `Keypair` on the `prehashed_message`.
     ///
     /// # Examples
     ///
     /// ```
     /// extern crate ed25519_dalek;
     /// extern crate rand;
-    /// extern crate sha2;
     ///
+    /// use ed25519_dalek::Digest;
     /// use ed25519_dalek::Keypair;
     /// use ed25519_dalek::Signature;
+    /// use ed25519_dalek::Sha512;
     /// use rand::thread_rng;
-    /// use sha2::Digest;
-    /// use sha2::Sha512;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// let mut csprng = thread_rng();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     /// let message: &[u8] = b"All I want is to pet all of the dogs.";
     ///
     /// let mut prehashed: Sha512 = Sha512::default();
     /// prehashed.input(message);
     ///
     /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
     ///
     /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context));
     ///
     /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one:
     /// let mut prehashed_again: Sha512 = Sha512::default();
     /// prehashed_again.input(message);
     ///
     /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig);
     ///
     /// assert!(verified.is_ok());
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
-    pub fn verify_prehashed<D>(&self,
-                               prehashed_message: D,
-                               context: Option<&[u8]>,
-                               signature: &Signature) -> Result<(), SignatureError>
-        where D: Digest<OutputSize = U64> + Default
+    pub fn verify_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&[u8]>,
+        signature: &Signature
+    ) -> Result<(), SignatureError>
+        where
+            D: Digest<OutputSize = U64>,
     {
-        self.public.verify_prehashed::<D>(prehashed_message, context, signature)
+        self.public.verify_prehashed(prehashed_message, context, signature)
     }
 }

 #[cfg(feature = "serde")]
 impl Serialize for Keypair {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
         serializer.serialize_bytes(&self.to_bytes()[..])
     }
 }

@@ -1428,29 +1394,29 @@ mod test {
     fn sign_verify() {  // TestSignVerify
         let mut csprng: ThreadRng;
         let keypair: Keypair;
         let good_sig: Signature;
         let bad_sig:  Signature;

         let good: &[u8] = "test message".as_bytes();
         let bad:  &[u8] = "wrong message".as_bytes();

         csprng  = thread_rng();
-        keypair  = Keypair::generate::<Sha512, _>(&mut csprng);
-        good_sig = keypair.sign::<Sha512>(&good);
-        bad_sig  = keypair.sign::<Sha512>(&bad);
+        keypair  = Keypair::generate(&mut csprng);
+        good_sig = keypair.sign(&good);
+        bad_sig  = keypair.sign(&bad);

-        assert!(keypair.verify::<Sha512>(&good, &good_sig).is_ok(),
+        assert!(keypair.verify(&good, &good_sig).is_ok(),
                 "Verification of a valid signature failed!");
-        assert!(keypair.verify::<Sha512>(&good, &bad_sig).is_err(),
+        assert!(keypair.verify(&good, &bad_sig).is_err(),
                 "Verification of a signature on a different message passed!");
-        assert!(keypair.verify::<Sha512>(&bad,  &good_sig).is_err(),
+        assert!(keypair.verify(&bad,  &good_sig).is_err(),
                 "Verification of a signature on a different message passed!");
     }

     // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang
     // package. It is a selection of test cases from
     // http://ed25519.cr.yp.to/python/sign.input
     #[cfg(test)]
     #[cfg(not(release))]
     #[test]
     fn golden() { // TestGolden
@@ -1478,24 +1444,24 @@ mod test {
             let msg_bytes: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap();
             let sig_bytes: Vec<u8> = FromHex::from_hex(&parts[3]).unwrap();

             let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap();
             let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap();
             let keypair: Keypair  = Keypair{ secret: secret, public: public };

 		    // The signatures in the test vectors also include the message
 		    // at the end, but we just want R and S.
             let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap();
-            let sig2: Signature = keypair.sign::<Sha512>(&msg_bytes);
+            let sig2: Signature = keypair.sign(&msg_bytes);

             assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno);
-            assert!(keypair.verify::<Sha512>(&msg_bytes, &sig2).is_ok(),
+            assert!(keypair.verify(&msg_bytes, &sig2).is_ok(),
                     "Signature verification failed on line {}", lineno);
         }
     }

     // From https://tools.ietf.org/html/rfc8032#section-7.3
     #[test]
     fn ed25519ph_rf8032_test_vector() {
         let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42";
         let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf";
         let message: &[u8] = b"616263";
@@ -1545,54 +1511,54 @@ mod test {
         prehashed_good3.input(good);

         let mut prehashed_bad1: Sha512 = Sha512::default();
         prehashed_bad1.input(bad);
         let mut prehashed_bad2: Sha512 = Sha512::default();
         prehashed_bad2.input(bad);

         let context: &[u8] = b"testing testing 1 2 3";

         csprng   = thread_rng();
-        keypair  = Keypair::generate::<Sha512, _>(&mut csprng);
-        good_sig = keypair.sign_prehashed::<Sha512>(prehashed_good1, Some(context));
-        bad_sig  = keypair.sign_prehashed::<Sha512>(prehashed_bad1,  Some(context));
+        keypair  = Keypair::generate(&mut csprng);
+        good_sig = keypair.sign_prehashed(prehashed_good1, Some(context));
+        bad_sig  = keypair.sign_prehashed(prehashed_bad1,  Some(context));

-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_good2, Some(context), &good_sig).is_ok(),
+        assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(),
                 "Verification of a valid signature failed!");
-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_good3, Some(context), &bad_sig).is_err(),
+        assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(),
                 "Verification of a signature on a different message passed!");
-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_bad2,  Some(context), &good_sig).is_err(),
+        assert!(keypair.verify_prehashed(prehashed_bad2,  Some(context), &good_sig).is_err(),
                 "Verification of a signature on a different message passed!");
     }

     #[test]
     fn verify_batch_seven_signatures() {
         let messages: [&[u8]; 7] = [
             b"Watch closely everyone, I'm going to show you how to kill a god.",
             b"I'm not a cryptographer I just encrypt a lot.",
             b"Still not a cryptographer.",
             b"This is a test of the tsunami alert system. This is only a test.",
             b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.",
             b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.",
             b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ];
         let mut csprng: ThreadRng = thread_rng();
         let mut keypairs: Vec<Keypair> = Vec::new();
         let mut signatures: Vec<Signature> = Vec::new();

         for i in 0..messages.len() {
-            let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-            signatures.push(keypair.sign::<Sha512>(&messages[i]));
+            let keypair: Keypair = Keypair::generate(&mut csprng);
+            signatures.push(keypair.sign(&messages[i]));
             keypairs.push(keypair);
         }
         let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect();

-        let result = verify_batch::<Sha512>(&messages, &signatures[..], &public_keys[..]);
+        let result = verify_batch(&messages, &signatures[..], &public_keys[..]);

         assert!(result.is_ok());
     }

     #[test]
     fn public_key_from_bytes() {
         // Make another function so that we can test the ? operator.
         fn do_the_test() -> Result<PublicKey, SignatureError> {
             let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
                 215, 090, 152, 001, 130, 177, 010, 183,
@@ -1629,24 +1595,24 @@ mod test {
                 slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x))
             }
         }

         assert!(!as_bytes(&keypair).contains(&0x15));
     }

     #[test]
     fn pubkey_from_secret_and_expanded_secret() {
         let mut csprng = thread_rng();
-        let secret: SecretKey = SecretKey::generate::<_>(&mut csprng);
-        let expanded_secret: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::<Sha512>(&secret);
-        let public_from_secret: PublicKey = PublicKey::from_secret::<Sha512>(&secret);
-        let public_from_expanded_secret: PublicKey = PublicKey::from_expanded_secret(&expanded_secret);
+        let secret: SecretKey = SecretKey::generate(&mut csprng);
+        let expanded_secret: ExpandedSecretKey = (&secret).into();
+        let public_from_secret: PublicKey = (&secret).into(); // XXX eww
+        let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww

         assert!(public_from_secret == public_from_expanded_secret);
     }

     #[cfg(all(test, feature = "serde"))]
     use bincode::{serialize, serialized_size, deserialize, Infinite};

     #[cfg(all(test, feature = "serde"))]
     #[test]
     fn serialize_deserialize_signature() {
diff --git c/src/lib.rs i/src/lib.rs
index ff8ed03..b0854ba 100644
--- c/src/lib.rs
+++ i/src/lib.rs
@@ -8,156 +8,143 @@
 // - Isis Agora Lovecruft <isis@patternsinthevoid.net>

 //! ed25519 signatures and verification
 //!
 //! # Example
 //!
 //! Creating an ed25519 signature on a message is simple.
 //!
 //! First, we need to generate a `Keypair`, which includes both public and
 //! secret halves of an asymmetric key.  To do so, we need a cryptographically
-//! secure pseudorandom number generator (CSPRNG), and a hash function which
-//! has 512 bits of output.  For this example, we'll use the operating
-//! system's builtin PRNG and SHA-512 to generate a keypair:
+//! secure pseudorandom number generator (CSPRNG). For this example, we'll use
+//! the operating system's builtin PRNG:
 //!
 //! ```
 //! extern crate rand;
-//! extern crate sha2;
 //! extern crate ed25519_dalek;
 //!
-//! # #[cfg(all(feature = "std", feature = "sha2"))]
+//! # #[cfg(feature = "std")]
 //! # fn main() {
 //! use rand::Rng;
 //! use rand::OsRng;
-//! use sha2::Sha512;
 //! use ed25519_dalek::Keypair;
 //! use ed25519_dalek::Signature;
 //!
 //! let mut csprng: OsRng = OsRng::new().unwrap();
-//! let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); // The `_` can be the type of `csprng`
+//! let keypair: Keypair = Keypair::generate(&mut csprng);
 //! # }
 //! #
-//! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))]
+//! # #[cfg(not(feature = "std"))]
 //! # fn main() { }
 //! ```
 //!
 //! We can now use this `keypair` to sign a message:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! let signature: Signature = keypair.sign(message);
 //! # }
 //! ```
 //!
 //! As well as to verify that this is, indeed, a valid signature on
 //! that `message`:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
-//! assert!(keypair.verify::<Sha512>(message, &signature).is_ok());
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
+//! assert!(keypair.verify(message, &signature).is_ok());
 //! # }
 //! ```
 //!
 //! Anyone else, given the `public` half of the `keypair` can also easily
 //! verify this signature:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! use ed25519_dalek::PublicKey;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //!
 //! let public_key: PublicKey = keypair.public;
-//! assert!(public_key.verify::<Sha512>(message, &signature).is_ok());
+//! assert!(public_key.verify(message, &signature).is_ok());
 //! # }
 //! ```
 //!
 //! ## Serialisation
 //!
 //! `PublicKey`s, `SecretKey`s, `Keypair`s, and `Signature`s can be serialised
 //! into byte-arrays by calling `.to_bytes()`.  It's perfectly acceptible and
 //! safe to transfer and/or store those bytes.  (Of course, never transfer your
 //! secret key to anyone else, since they will only need the public key to
 //! verify your signatures!)
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
 //!
 //! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes();
 //! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes();
 //! let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair.to_bytes();
 //! let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature.to_bytes();
 //! # }
 //! ```
 //!
 //! And similarly, decoded from bytes with `::from_bytes()`:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError};
 //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
 //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> {
 //! # let mut csprng = thread_rng();
-//! # let keypair_orig: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature_orig: Signature = keypair_orig.sign::<Sha512>(message);
+//! # let keypair_orig: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature_orig: Signature = keypair_orig.sign(message);
 //! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes();
 //! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes();
 //! # let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair_orig.to_bytes();
 //! # let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature_orig.to_bytes();
 //! #
 //! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?;
 //! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?;
 //! let keypair:    Keypair   = Keypair::from_bytes(&keypair_bytes)?;
 //! let signature:  Signature = Signature::from_bytes(&signature_bytes)?;
 //! #
@@ -176,84 +163,80 @@
 //!
 //! ```bash
 //! $ cargo build --features="serde"
 //! ```
 //!
 //! They can be then serialised into any of the wire formats which serde supports.
 //! For example, using [bincode](https://github.com/TyOverby/bincode):
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # #[cfg(feature = "serde")]
 //! extern crate serde;
 //! # #[cfg(feature = "serde")]
 //! extern crate bincode;
 //!
 //! # #[cfg(feature = "serde")]
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! use bincode::{serialize, Infinite};
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
-//! # let verified: bool = public_key.verify::<Sha512>(message, &signature).is_ok();
+//! # let verified: bool = public_key.verify(message, &signature).is_ok();
 //!
 //! let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
 //! let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
 //! # }
 //! # #[cfg(not(feature = "serde"))]
 //! # fn main() {}
 //! ```
 //!
 //! After sending the `encoded_public_key` and `encoded_signature`, the
 //! recipient may deserialise them and verify:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # #[cfg(feature = "serde")]
 //! # extern crate serde;
 //! # #[cfg(feature = "serde")]
 //! # extern crate bincode;
 //! #
 //! # #[cfg(feature = "serde")]
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! # use bincode::{serialize, Infinite};
 //! use bincode::{deserialize};
 //!
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
-//! # let verified: bool = public_key.verify::<Sha512>(message, &signature).is_ok();
+//! # let verified: bool = public_key.verify(message, &signature).is_ok();
 //! # let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
 //! # let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
 //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
 //! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
 //!
 //! # assert_eq!(public_key, decoded_public_key);
 //! # assert_eq!(signature, decoded_signature);
 //! #
-//! let verified: bool = decoded_public_key.verify::<Sha512>(&message, &decoded_signature).is_ok();
+//! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok();
 //!
 //! assert!(verified);
 //! # }
 //! # #[cfg(not(feature = "serde"))]
 //! # fn main() {}
 //! ```

 #![no_std]
 #![allow(unused_features)]
 #![deny(missing_docs)] // refuse to compile if documentation is missing
isislovecruft added a commit to isislovecruft/ed25519-dalek that referenced this issue Dec 30, 2018
This implements dalek-cryptography#64

You can still choose the "prehash" algorithm, as long as it has 64 bytes of
output.  Otherwise, everything is hardcoded to use sha2::Sha512.  To use a
different implementation you'll need a [patch.crates-io] section in cargo
config.

diff --git c/Cargo.toml i/Cargo.toml
index 5b04835..5d5cc94 100644
--- c/Cargo.toml
+++ i/Cargo.toml
@@ -22,40 +22,39 @@ default-features = false
 [dependencies.rand]
 version = "0.6"
 features = ["i128_support"]

 [dependencies.serde]
 version = "^1.0"
 optional = true

 [dependencies.sha2]
 version = "^0.8"
-optional = true
+default-features = false

 [dependencies.failure]
 version = "^0.1.1"
 default-features = false

 [dependencies.clear_on_drop]
 version = "0.2"

 [dev-dependencies]
 hex = "^0.3"
-sha2 = "^0.8"
 bincode = "^0.9"
 criterion = "0.2"

 [[bench]]
 name = "ed25519_benchmarks"
 harness = false

 [features]
 default = ["std", "u64_backend"]
 # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies.
-std = ["curve25519-dalek/std", "rand/std"]
+std = ["curve25519-dalek/std", "rand/std", "sha2/std"]
 alloc = ["curve25519-dalek/alloc"]
 nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"]
 asm = ["sha2/asm"]
 yolocrypto = ["curve25519-dalek/yolocrypto"]
 u64_backend = ["curve25519-dalek/u64_backend"]
 u32_backend = ["curve25519-dalek/u32_backend"]
 avx2_backend = ["curve25519-dalek/avx2_backend"]
diff --git c/src/ed25519.rs i/src/ed25519.rs
index 4d2fabd..c7f5c69 100644
--- c/src/ed25519.rs
+++ i/src/ed25519.rs
@@ -1,43 +1,41 @@
 // -*- mode: rust; -*-
 //
 // This file is part of ed25519-dalek.
 // Copyright (c) 2017-2018 Isis Lovecruft
 // See LICENSE for licensing information.
 //
 // Authors:
 // - Isis Agora Lovecruft <isis@patternsinthevoid.net>

-//! A Rust implementation of ed25519 EdDSA key generation, signing, and
-//! verification.
+//! A Rust implementation of ed25519 key generation, signing, and verification.

 use core::default::Default;
 use core::fmt::{Debug};

 use rand::CryptoRng;
 use rand::Rng;

 #[cfg(feature = "serde")]
 use serde::{Serialize, Deserialize};
 #[cfg(feature = "serde")]
 use serde::{Serializer, Deserializer};
 #[cfg(feature = "serde")]
 use serde::de::Error as SerdeError;
 #[cfg(feature = "serde")]
 use serde::de::Visitor;

-#[cfg(feature = "sha2")]
-use sha2::Sha512;
+pub use sha2::Sha512;

 use clear_on_drop::clear::Clear;

-use curve25519_dalek::digest::Digest;
+pub use curve25519_dalek::digest::Digest;
 use curve25519_dalek::digest::generic_array::typenum::U64;

 use curve25519_dalek::constants;
 use curve25519_dalek::edwards::CompressedEdwardsY;
 use curve25519_dalek::edwards::EdwardsPoint;
 use curve25519_dalek::scalar::Scalar;

 use errors::SignatureError;
 use errors::InternalError;

@@ -181,27 +179,20 @@ impl Drop for SecretKey {
     }
 }

 impl AsRef<[u8]> for SecretKey {
     fn as_ref(&self) -> &[u8] {
         self.as_bytes()
     }
 }

 impl SecretKey {
-    /// Expand this `SecretKey` into an `ExpandedSecretKey`.
-    pub fn expand<D>(&self) -> ExpandedSecretKey
-        where D: Digest<OutputSize = U64> + Default
-    {
-        ExpandedSecretKey::from_secret_key::<D>(&self)
-    }
-
     /// Convert this secret key to a byte array.
     #[inline]
     pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
         self.0
     }

     /// View this secret key as a byte array.
     #[inline]
     pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] {
         &self.0
@@ -272,52 +263,44 @@ impl SecretKey {
     /// use ed25519_dalek::Signature;
     ///
     /// let mut csprng: OsRng = OsRng::new().unwrap();
     /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     /// # }
     /// #
     /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
-    /// Afterwards, you can generate the corresponding public—provided you also
-    /// supply a hash function which implements the `Digest` and `Default`
-    /// traits, and which returns 512 bits of output—via:
+    /// Afterwards, you can generate the corresponding public:
     ///
     /// ```
     /// # extern crate rand;
-    /// # extern crate sha2;
     /// # extern crate ed25519_dalek;
     /// #
     /// # fn main() {
     /// #
     /// # use rand::Rng;
     /// # use rand::thread_rng;
-    /// # use sha2::Sha512;
     /// # use ed25519_dalek::PublicKey;
     /// # use ed25519_dalek::SecretKey;
     /// # use ed25519_dalek::Signature;
     /// #
     /// # let mut csprng = thread_rng();
     /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     ///
-    /// let public_key: PublicKey = PublicKey::from_secret::<Sha512>(&secret_key);
+    /// let public_key: PublicKey = (&secret_key).into();
     /// # }
     /// ```
     ///
-    /// The standard hash function used for most ed25519 libraries is SHA-512,
-    /// which is available with `use sha2::Sha512` as in the example above.
-    /// Other suitable hash functions include Keccak-512 and Blake2b-512.
-    ///
     /// # Input
     ///
-    /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`
+    /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng`
     pub fn generate<T>(csprng: &mut T) -> SecretKey
         where T: CryptoRng + Rng,
     {
         let mut sk: SecretKey = SecretKey([0u8; 32]);

         csprng.fill_bytes(&mut sk.0);

         sk
     }
 }
@@ -391,49 +374,59 @@ pub struct ExpandedSecretKey {
 }

 /// Overwrite secret key material with null bytes when it goes out of scope.
 impl Drop for ExpandedSecretKey {
     fn drop(&mut self) {
         self.key.clear();
         self.nonce.clear();
     }
 }

-#[cfg(feature = "sha2")]
 impl<'a> From<&'a SecretKey> for ExpandedSecretKey {
     /// Construct an `ExpandedSecretKey` from a `SecretKey`.
     ///
     /// # Examples
     ///
     /// ```
     /// # extern crate rand;
     /// # extern crate sha2;
     /// # extern crate ed25519_dalek;
     /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
     /// # fn main() {
     /// #
     /// use rand::Rng;
-    /// use rand::rngs::OsRng;
+    /// use rand::thread_rng;
     /// use sha2::Sha512;
     /// use ed25519_dalek::{SecretKey, ExpandedSecretKey};
     ///
-    /// let mut csprng: OsRng = OsRng::new().unwrap();
+    /// let mut csprng = thread_rng();
     /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
     /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key);
     /// # }
-    /// #
-    /// # #[cfg(any(not(feature = "std"), not(feature = "sha2")))]
-    /// # fn main() {}
     /// ```
     fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey {
-        ExpandedSecretKey::from_secret_key::<Sha512>(&secret_key)
+        let mut h: Sha512 = Sha512::default();
+        let mut hash:  [u8; 64] = [0u8; 64];
+        let mut lower: [u8; 32] = [0u8; 32];
+        let mut upper: [u8; 32] = [0u8; 32];
+
+        h.input(secret_key.as_bytes());
+        hash.copy_from_slice(h.result().as_slice());
+
+        lower.copy_from_slice(&hash[00..32]);
+        upper.copy_from_slice(&hash[32..64]);
+
+        lower[0]  &= 248;
+        lower[31] &=  63;
+        lower[31] |=  64;
+
+        ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, }
     }
 }

 impl ExpandedSecretKey {
     /// Convert this `ExpandedSecretKey` into an array of 64 bytes.
     ///
     /// # Returns
     ///
     /// An array of 64 bytes.  The first 32 bytes represent the "expanded"
     /// secret key, and the last 32 bytes represent the "domain-separation"
@@ -525,82 +518,36 @@ impl ExpandedSecretKey {
         let mut lower: [u8; 32] = [0u8; 32];
         let mut upper: [u8; 32] = [0u8; 32];

         lower.copy_from_slice(&bytes[00..32]);
         upper.copy_from_slice(&bytes[32..64]);

         Ok(ExpandedSecretKey{ key:   Scalar::from_bits(lower),
                               nonce:                   upper  })
     }

-    /// Construct an `ExpandedSecretKey` from a `SecretKey`, using hash function `D`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # extern crate rand;
-    /// # extern crate sha2;
-    /// # extern crate ed25519_dalek;
-    /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
-    /// # fn main() {
-    /// #
-    /// use rand::Rng;
-    /// use rand::rngs::OsRng;
-    /// use sha2::Sha512;
-    /// use ed25519_dalek::{SecretKey, ExpandedSecretKey};
-    ///
-    /// let mut csprng: OsRng = OsRng::new().unwrap();
-    /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
-    /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::<Sha512>(&secret_key);
-    /// # }
-    /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
-    /// # fn main() { }
-    /// ```
-    pub fn from_secret_key<D>(secret_key: &SecretKey) -> ExpandedSecretKey
-            where D: Digest<OutputSize = U64> + Default {
-        let mut h: D = D::default();
-        let mut hash:  [u8; 64] = [0u8; 64];
-        let mut lower: [u8; 32] = [0u8; 32];
-        let mut upper: [u8; 32] = [0u8; 32];
-
-        h.input(secret_key.as_bytes());
-        hash.copy_from_slice(h.result().as_slice());
-
-        lower.copy_from_slice(&hash[00..32]);
-        upper.copy_from_slice(&hash[32..64]);
-
-        lower[0]  &= 248;
-        lower[31] &=  63;
-        lower[31] |=  64;
-
-        ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, }
-    }
-
     /// Sign a message with this `ExpandedSecretKey`.
     #[allow(non_snake_case)]
-    pub fn sign<D>(&self, message: &[u8], public_key: &PublicKey) -> Signature
-            where D: Digest<OutputSize = U64> + Default {
-        let mut h: D = D::default();
+    pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature {
+        let mut h: Sha512 = Sha512::new();
         let R: CompressedEdwardsY;
         let r: Scalar;
         let s: Scalar;
         let k: Scalar;

         h.input(&self.nonce);
         h.input(&message);

         r = Scalar::from_hash(h);
         R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();

-        h = D::default();
+        h = Sha512::new();
         h.input(R.as_bytes());
         h.input(public_key.as_bytes());
         h.input(&message);

         k = Scalar::from_hash(h);
         s = &(&k * &self.key) + &r;

         Signature{ R, s }
     }

@@ -616,27 +563,30 @@ impl ExpandedSecretKey {
     /// * `context` is an optional context string, up to 255 bytes inclusive,
     ///   which may be used to provide additional domain separation.  If not
     ///   set, this will default to an empty string.
     ///
     /// # Returns
     ///
     /// An Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     #[allow(non_snake_case)]
-    pub fn sign_prehashed<D>(&self,
-                             prehashed_message: D,
-                             public_key: &PublicKey,
-                             context: Option<&'static [u8]>) -> Signature
-        where D: Digest<OutputSize = U64> + Default
+    pub fn sign_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        public_key: &PublicKey,
+        context: Option<&'static [u8]>,
+    ) -> Signature
+        where
+            D: Digest<OutputSize = U64>,
     {
-        let mut h: D;
+        let mut h: Sha512;
         let mut prehash: [u8; 64] = [0u8; 64];
         let R: CompressedEdwardsY;
         let r: Scalar;
         let s: Scalar;
         let k: Scalar;

         let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string.

         debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");

@@ -650,32 +600,32 @@ impl ExpandedSecretKey {
         // the upper half "prefix" of the hashed "secret key" in here?  Why
         // can't the user just supply their own nonce and decide for themselves
         // whether or not they want a deterministic signature scheme?  Why does
         // the message go into what's ostensibly the signature domain separation
         // hash?  Why wasn't there always a way to provide a context string?
         //
         // ...
         //
         // This is a really fucking stupid bandaid, and the damned scheme is
         // still bleeding from malleability, for fuck's sake.
-        h = D::default()
+        h = Sha512::new()
             .chain(b"SigEd25519 no Ed25519 collisions")
             .chain(&[1]) // Ed25519ph
             .chain(&[ctx_len])
             .chain(ctx)
             .chain(&self.nonce)
             .chain(&prehash[..]);

         r = Scalar::from_hash(h);
         R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();

-        h = D::default()
+        h = Sha512::new()
             .chain(b"SigEd25519 no Ed25519 collisions")
             .chain(&[1]) // Ed25519ph
             .chain(&[ctx_len])
             .chain(ctx)
             .chain(R.as_bytes())
             .chain(public_key.as_bytes())
             .chain(&prehash[..]);

         k = Scalar::from_hash(h);
         s = &(&k * &self.key) + &r;
@@ -787,69 +737,75 @@ impl PublicKey {
                 name: "PublicKey", length: PUBLIC_KEY_LENGTH }));
         }
         let mut bits: [u8; 32] = [0u8; 32];
         bits.copy_from_slice(&bytes[..32]);

         let compressed = CompressedEdwardsY(bits);
         let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?;

         Ok(PublicKey(compressed, point))
     }
+}

+impl<'a> From<&'a SecretKey> for PublicKey {
     /// Derive this public key from its corresponding `SecretKey`.
-    #[allow(unused_assignments)]
-    pub fn from_secret<D>(secret_key: &SecretKey) -> PublicKey
-        where D: Digest<OutputSize = U64> + Default
-    {
-        let mut h:    D = D::default();
+    fn from(secret_key: &SecretKey) -> PublicKey {
+        let mut h:    Sha512 = Sha512::new();
         let mut hash:   [u8; 64] = [0u8; 64];
         let mut digest: [u8; 32] = [0u8; 32];

         h.input(secret_key.as_bytes());
         hash.copy_from_slice(h.result().as_slice());

         digest.copy_from_slice(&hash[..32]);

         PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest)
     }
+}

+impl<'a> From<&'a ExpandedSecretKey> for PublicKey {
     /// Derive this public key from its corresponding `ExpandedSecretKey`.
-    pub fn from_expanded_secret(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
+    fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey {
         let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes();

         PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits)
     }
+}

+impl PublicKey {
     /// Internal utility function for mangling the bits of a (formerly
     /// mathematically well-defined) "scalar" and multiplying it to produce a
     /// public key.
     fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey {
         bits[0]  &= 248;
         bits[31] &= 127;
         bits[31] |= 64;

         let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE;
         let compressed = point.compress();

         PublicKey(compressed, point)
     }

     /// Verify a signature on a message with this keypair's public key.
     ///
     /// # Return
     ///
     /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
     #[allow(non_snake_case)]
-    pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError>
-            where D: Digest<OutputSize = U64> + Default
+    pub fn verify(
+        &self,
+        message: &[u8],
+        signature: &Signature
+    ) -> Result<(), SignatureError>
     {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::new();
         let R: EdwardsPoint;
         let k: Scalar;
         let minus_A: EdwardsPoint = -self.1;

         h.input(signature.R.as_bytes());
         h.input(self.as_bytes());
         h.input(&message);

         k = Scalar::from_hash(h);
         R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s);
@@ -873,27 +829,30 @@ impl PublicKey {
     ///   set, this will default to an empty string.
     /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// # Returns
     ///
     /// Returns `true` if the `signature` was a valid signature created by this
     /// `Keypair` on the `prehashed_message`.
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     #[allow(non_snake_case)]
-    pub fn verify_prehashed<D>(&self,
-                               prehashed_message: D,
-                               context: Option<&[u8]>,
-                               signature: &Signature) -> Result<(), SignatureError>
-        where D: Digest<OutputSize = U64> + Default
+    pub fn verify_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&[u8]>,
+        signature: &Signature,
+    ) -> Result<(), SignatureError>
+        where
+            D: Digest<OutputSize = U64>,
     {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::default();
         let R: EdwardsPoint;
         let k: Scalar;

         let ctx: &[u8] = context.unwrap_or(b"");
         debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets.");

         let minus_A: EdwardsPoint = -self.1;

         h.input(b"SigEd25519 no Ed25519 collisions");
         h.input(&[1]); // Ed25519ph
@@ -939,48 +898,47 @@ impl From<ExpandedSecretKey> for PublicKey {
 ///
 /// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a
 ///   `SignatureError` containing a description of the internal error which
 ///   occured.
 ///
 /// # Examples
 ///
 /// ```
 /// extern crate ed25519_dalek;
 /// extern crate rand;
-/// extern crate sha2;
 ///
 /// use ed25519_dalek::verify_batch;
 /// use ed25519_dalek::Keypair;
 /// use ed25519_dalek::PublicKey;
 /// use ed25519_dalek::Signature;
 /// use rand::thread_rng;
 /// use rand::rngs::ThreadRng;
-/// use sha2::Sha512;
 ///
 /// # fn main() {
 /// let mut csprng: ThreadRng = thread_rng();
-/// let keypairs: Vec<Keypair> = (0..64).map(|_| Keypair::generate::<Sha512, _>(&mut csprng)).collect();
+/// let keypairs: Vec<Keypair> = (0..64).map(|_| Keypair::generate(&mut csprng)).collect();
 /// let msg: &[u8] = b"They're good dogs Brant";
 /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect();
-/// let signatures:  Vec<Signature> = keypairs.iter().map(|key| key.sign::<Sha512>(&msg)).collect();
+/// let signatures:  Vec<Signature> = keypairs.iter().map(|key| key.sign(&msg)).collect();
 /// let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect();
 ///
-/// let result = verify_batch::<Sha512>(&messages[..], &signatures[..], &public_keys[..]);
+/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]);
 /// assert!(result.is_ok());
 /// # }
 /// ```
 #[cfg(any(feature = "alloc", feature = "std"))]
 #[allow(non_snake_case)]
-pub fn verify_batch<D>(messages: &[&[u8]],
-                       signatures: &[Signature],
-                       public_keys: &[PublicKey]) -> Result<(), SignatureError>
-    where D: Digest<OutputSize = U64> + Default
+pub fn verify_batch(
+    messages: &[&[u8]],
+    signatures: &[Signature],
+    public_keys: &[PublicKey],
+) -> Result<(), SignatureError>
 {
     const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal.";
     assert!(signatures.len()  == messages.len(),    ASSERT_MESSAGE);
     assert!(signatures.len()  == public_keys.len(), ASSERT_MESSAGE);
     assert!(public_keys.len() == messages.len(),    ASSERT_MESSAGE);

     #[cfg(feature = "alloc")]
     use alloc::vec::Vec;
     #[cfg(feature = "std")]
     use std::vec::Vec;
@@ -1000,21 +958,21 @@ pub fn verify_batch<D>(messages: &[&[u8]],
     // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l)
     let B_coefficient: Scalar = signatures
         .iter()
         .map(|sig| sig.s)
         .zip(zs.iter())
         .map(|(s, z)| z * s)
         .sum();

     // Compute H(R || A || M) for each (signature, public_key, message) triplet
     let hrams = (0..signatures.len()).map(|i| {
-        let mut h: D = D::default();
+        let mut h: Sha512 = Sha512::default();
         h.input(signatures[i].R.as_bytes());
         h.input(public_keys[i].as_bytes());
         h.input(&messages[i]);
         Scalar::from_hash(h)
     });

     // Multiply each H(R || A || M) by the random value
     let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z);

     let Rs = signatures.iter().map(|sig| sig.R.decompress());
@@ -1118,64 +1076,63 @@ impl Keypair {

         Ok(Keypair{ secret: secret, public: public })
     }

     /// Generate an ed25519 keypair.
     ///
     /// # Example
     ///
     /// ```
     /// extern crate rand;
-    /// extern crate sha2;
     /// extern crate ed25519_dalek;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     ///
     /// use rand::Rng;
     /// use rand::OsRng;
-    /// use sha2::Sha512;
     /// use ed25519_dalek::Keypair;
     /// use ed25519_dalek::Signature;
     ///
     /// let mut csprng: OsRng = OsRng::new().unwrap();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     ///
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// # Input
     ///
     /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`.
     ///
     /// The caller must also supply a hash function which implements the
     /// `Digest` and `Default` traits, and which returns 512 bits of output.
     /// The standard hash function used for most ed25519 libraries is SHA-512,
     /// which is available with `use sha2::Sha512` as in the example above.
     /// Other suitable hash functions include Keccak-512 and Blake2b-512.
-    pub fn generate<D, R>(csprng: &mut R) -> Keypair
-        where D: Digest<OutputSize = U64> + Default,
-              R: CryptoRng + Rng,
+    pub fn generate<R>(csprng: &mut R) -> Keypair
+        where R: CryptoRng + Rng,
     {
         let sk: SecretKey = SecretKey::generate(csprng);
-        let pk: PublicKey = PublicKey::from_secret::<D>(&sk);
+        let pk: PublicKey = (&sk).into();

         Keypair{ public: pk, secret: sk }
     }

     /// Sign a message with this keypair's secret key.
-    pub fn sign<D>(&self, message: &[u8]) -> Signature
-            where D: Digest<OutputSize = U64> + Default {
-        self.secret.expand::<D>().sign::<D>(&message, &self.public)
+    pub fn sign(&self, message: &[u8]) -> Signature
+    {
+        let expanded: ExpandedSecretKey = (&self.secret).into();
+
+        expanded.sign(&message, &self.public)
     }

     /// Sign a `prehashed_message` with this `Keypair` using the
     /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032].
     ///
     /// # Inputs
     ///
     /// * `prehashed_message` is an instantiated hash digest with 512-bits of
     ///   output which has had the message to be signed previously fed into its
     ///   state.
@@ -1185,41 +1142,40 @@ impl Keypair {
     ///
     /// # Returns
     ///
     /// An Ed25519ph [`Signature`] on the `prehashed_message`.
     ///
     /// # Examples
     ///
     /// ```
     /// extern crate ed25519_dalek;
     /// extern crate rand;
-    /// extern crate sha2;
     ///
+    /// use ed25519_dalek::Digest;
     /// use ed25519_dalek::Keypair;
+    /// use ed25519_dalek::Sha512;
     /// use ed25519_dalek::Signature;
     /// use rand::thread_rng;
-    /// use sha2::Digest;
-    /// use sha2::Sha512;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// let mut csprng = thread_rng();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     /// let message: &[u8] = b"All I want is to pet all of the dogs.";
     ///
     /// // Create a hash digest object which we'll feed the message into:
-    /// let mut prehashed: Sha512 = Sha512::default();
+    /// let mut prehashed: Sha512 = Sha512::new();
     ///
     /// prehashed.input(message);
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// If you want, you can optionally pass a "context".  It is generally a
     /// good idea to choose a context and try to make it unique to your project
     /// and this specific usage of signatures.
     ///
     /// For example, without this, if you were to [convert your OpenPGP key
     /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't
     /// Ever Do That) and someone tricked you into signing an "email" which was
@@ -1233,59 +1189,67 @@ impl Keypair {
     /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol",
     /// then the signatures produced by both could never match the other, even
     /// if they signed the exact same message with the same key.
     ///
     /// Let's add a context for good measure (remember, you'll want to choose
     /// your own!):
     ///
     /// ```
     /// # extern crate ed25519_dalek;
     /// # extern crate rand;
-    /// # extern crate sha2;
     /// #
+    /// # use ed25519_dalek::Digest;
     /// # use ed25519_dalek::Keypair;
     /// # use ed25519_dalek::Signature;
+    /// # use ed25519_dalek::Sha512;
     /// # use rand::thread_rng;
-    /// # use sha2::Digest;
-    /// # use sha2::Sha512;
     /// #
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// # let mut csprng = thread_rng();
-    /// # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// # let keypair: Keypair = Keypair::generate(&mut csprng);
     /// # let message: &[u8] = b"All I want is to pet all of the dogs.";
-    /// # let mut prehashed: Sha512 = Sha512::default();
+    /// # let mut prehashed: Sha512 = Sha512::new();
     /// # prehashed.input(message);
     /// #
     /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
     ///
     /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context));
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
     /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py
-    pub fn sign_prehashed<D>(&self,
-                             prehashed_message: D,
-                             context: Option<&'static [u8]>) -> Signature
-        where D: Digest<OutputSize = U64> + Default
+    pub fn sign_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&'static [u8]>
+    ) -> Signature
+        where
+            D: Digest<OutputSize = U64>,
     {
-        self.secret.expand::<D>().sign_prehashed::<D>(prehashed_message, &self.public, context)
+        let expanded: ExpandedSecretKey = (&self.secret).into();  // xxx thanks i hate this
+
+        expanded.sign_prehashed(prehashed_message, &self.public, context)
     }

     /// Verify a signature on a message with this keypair's public key.
-    pub fn verify<D>(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError>
-            where D: Digest<OutputSize = U64> + Default {
-        self.public.verify::<D>(message, signature)
+    pub fn verify(
+        &self,
+        message: &[u8],
+        signature: &Signature
+    ) -> Result<(), SignatureError>
+    {
+        self.public.verify(message, signature)
     }

     /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm.
     ///
     /// # Inputs
     ///
     /// * `prehashed_message` is an instantiated hash digest with 512-bits of
     ///   output which has had the message to be signed previously fed into its
     ///   state.
     /// * `context` is an optional context string, up to 255 bytes inclusive,
@@ -1296,62 +1260,64 @@ impl Keypair {
     /// # Returns
     ///
     /// Returns `true` if the `signature` was a valid signature created by this
     /// `Keypair` on the `prehashed_message`.
     ///
     /// # Examples
     ///
     /// ```
     /// extern crate ed25519_dalek;
     /// extern crate rand;
-    /// extern crate sha2;
     ///
+    /// use ed25519_dalek::Digest;
     /// use ed25519_dalek::Keypair;
     /// use ed25519_dalek::Signature;
+    /// use ed25519_dalek::Sha512;
     /// use rand::thread_rng;
-    /// use sha2::Digest;
-    /// use sha2::Sha512;
     ///
-    /// # #[cfg(all(feature = "std", feature = "sha2"))]
+    /// # #[cfg(feature = "std")]
     /// # fn main() {
     /// let mut csprng = thread_rng();
-    /// let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
+    /// let keypair: Keypair = Keypair::generate(&mut csprng);
     /// let message: &[u8] = b"All I want is to pet all of the dogs.";
     ///
     /// let mut prehashed: Sha512 = Sha512::default();
     /// prehashed.input(message);
     ///
     /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest";
     ///
     /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context));
     ///
     /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one:
     /// let mut prehashed_again: Sha512 = Sha512::default();
     /// prehashed_again.input(message);
     ///
     /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig);
     ///
     /// assert!(verified.is_ok());
     /// # }
     /// #
-    /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))]
+    /// # #[cfg(not(feature = "std"))]
     /// # fn main() { }
     /// ```
     ///
     /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
-    pub fn verify_prehashed<D>(&self,
-                               prehashed_message: D,
-                               context: Option<&[u8]>,
-                               signature: &Signature) -> Result<(), SignatureError>
-        where D: Digest<OutputSize = U64> + Default
+    pub fn verify_prehashed<D>(
+        &self,
+        prehashed_message: D,
+        context: Option<&[u8]>,
+        signature: &Signature
+    ) -> Result<(), SignatureError>
+        where
+            D: Digest<OutputSize = U64>,
     {
-        self.public.verify_prehashed::<D>(prehashed_message, context, signature)
+        self.public.verify_prehashed(prehashed_message, context, signature)
     }
 }

 #[cfg(feature = "serde")]
 impl Serialize for Keypair {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
         serializer.serialize_bytes(&self.to_bytes()[..])
     }
 }

@@ -1428,29 +1394,29 @@ mod test {
     fn sign_verify() {  // TestSignVerify
         let mut csprng: ThreadRng;
         let keypair: Keypair;
         let good_sig: Signature;
         let bad_sig:  Signature;

         let good: &[u8] = "test message".as_bytes();
         let bad:  &[u8] = "wrong message".as_bytes();

         csprng  = thread_rng();
-        keypair  = Keypair::generate::<Sha512, _>(&mut csprng);
-        good_sig = keypair.sign::<Sha512>(&good);
-        bad_sig  = keypair.sign::<Sha512>(&bad);
+        keypair  = Keypair::generate(&mut csprng);
+        good_sig = keypair.sign(&good);
+        bad_sig  = keypair.sign(&bad);

-        assert!(keypair.verify::<Sha512>(&good, &good_sig).is_ok(),
+        assert!(keypair.verify(&good, &good_sig).is_ok(),
                 "Verification of a valid signature failed!");
-        assert!(keypair.verify::<Sha512>(&good, &bad_sig).is_err(),
+        assert!(keypair.verify(&good, &bad_sig).is_err(),
                 "Verification of a signature on a different message passed!");
-        assert!(keypair.verify::<Sha512>(&bad,  &good_sig).is_err(),
+        assert!(keypair.verify(&bad,  &good_sig).is_err(),
                 "Verification of a signature on a different message passed!");
     }

     // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang
     // package. It is a selection of test cases from
     // http://ed25519.cr.yp.to/python/sign.input
     #[cfg(test)]
     #[cfg(not(release))]
     #[test]
     fn golden() { // TestGolden
@@ -1478,24 +1444,24 @@ mod test {
             let msg_bytes: Vec<u8> = FromHex::from_hex(&parts[2]).unwrap();
             let sig_bytes: Vec<u8> = FromHex::from_hex(&parts[3]).unwrap();

             let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap();
             let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap();
             let keypair: Keypair  = Keypair{ secret: secret, public: public };

 		    // The signatures in the test vectors also include the message
 		    // at the end, but we just want R and S.
             let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap();
-            let sig2: Signature = keypair.sign::<Sha512>(&msg_bytes);
+            let sig2: Signature = keypair.sign(&msg_bytes);

             assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno);
-            assert!(keypair.verify::<Sha512>(&msg_bytes, &sig2).is_ok(),
+            assert!(keypair.verify(&msg_bytes, &sig2).is_ok(),
                     "Signature verification failed on line {}", lineno);
         }
     }

     // From https://tools.ietf.org/html/rfc8032#section-7.3
     #[test]
     fn ed25519ph_rf8032_test_vector() {
         let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42";
         let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf";
         let message: &[u8] = b"616263";
@@ -1545,54 +1511,54 @@ mod test {
         prehashed_good3.input(good);

         let mut prehashed_bad1: Sha512 = Sha512::default();
         prehashed_bad1.input(bad);
         let mut prehashed_bad2: Sha512 = Sha512::default();
         prehashed_bad2.input(bad);

         let context: &[u8] = b"testing testing 1 2 3";

         csprng   = thread_rng();
-        keypair  = Keypair::generate::<Sha512, _>(&mut csprng);
-        good_sig = keypair.sign_prehashed::<Sha512>(prehashed_good1, Some(context));
-        bad_sig  = keypair.sign_prehashed::<Sha512>(prehashed_bad1,  Some(context));
+        keypair  = Keypair::generate(&mut csprng);
+        good_sig = keypair.sign_prehashed(prehashed_good1, Some(context));
+        bad_sig  = keypair.sign_prehashed(prehashed_bad1,  Some(context));

-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_good2, Some(context), &good_sig).is_ok(),
+        assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(),
                 "Verification of a valid signature failed!");
-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_good3, Some(context), &bad_sig).is_err(),
+        assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(),
                 "Verification of a signature on a different message passed!");
-        assert!(keypair.verify_prehashed::<Sha512>(prehashed_bad2,  Some(context), &good_sig).is_err(),
+        assert!(keypair.verify_prehashed(prehashed_bad2,  Some(context), &good_sig).is_err(),
                 "Verification of a signature on a different message passed!");
     }

     #[test]
     fn verify_batch_seven_signatures() {
         let messages: [&[u8]; 7] = [
             b"Watch closely everyone, I'm going to show you how to kill a god.",
             b"I'm not a cryptographer I just encrypt a lot.",
             b"Still not a cryptographer.",
             b"This is a test of the tsunami alert system. This is only a test.",
             b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.",
             b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.",
             b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ];
         let mut csprng: ThreadRng = thread_rng();
         let mut keypairs: Vec<Keypair> = Vec::new();
         let mut signatures: Vec<Signature> = Vec::new();

         for i in 0..messages.len() {
-            let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-            signatures.push(keypair.sign::<Sha512>(&messages[i]));
+            let keypair: Keypair = Keypair::generate(&mut csprng);
+            signatures.push(keypair.sign(&messages[i]));
             keypairs.push(keypair);
         }
         let public_keys: Vec<PublicKey> = keypairs.iter().map(|key| key.public).collect();

-        let result = verify_batch::<Sha512>(&messages, &signatures[..], &public_keys[..]);
+        let result = verify_batch(&messages, &signatures[..], &public_keys[..]);

         assert!(result.is_ok());
     }

     #[test]
     fn public_key_from_bytes() {
         // Make another function so that we can test the ? operator.
         fn do_the_test() -> Result<PublicKey, SignatureError> {
             let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [
                 215, 090, 152, 001, 130, 177, 010, 183,
@@ -1629,24 +1595,24 @@ mod test {
                 slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x))
             }
         }

         assert!(!as_bytes(&keypair).contains(&0x15));
     }

     #[test]
     fn pubkey_from_secret_and_expanded_secret() {
         let mut csprng = thread_rng();
-        let secret: SecretKey = SecretKey::generate::<_>(&mut csprng);
-        let expanded_secret: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::<Sha512>(&secret);
-        let public_from_secret: PublicKey = PublicKey::from_secret::<Sha512>(&secret);
-        let public_from_expanded_secret: PublicKey = PublicKey::from_expanded_secret(&expanded_secret);
+        let secret: SecretKey = SecretKey::generate(&mut csprng);
+        let expanded_secret: ExpandedSecretKey = (&secret).into();
+        let public_from_secret: PublicKey = (&secret).into(); // XXX eww
+        let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww

         assert!(public_from_secret == public_from_expanded_secret);
     }

     #[cfg(all(test, feature = "serde"))]
     use bincode::{serialize, serialized_size, deserialize, Infinite};

     #[cfg(all(test, feature = "serde"))]
     #[test]
     fn serialize_deserialize_signature() {
diff --git c/src/lib.rs i/src/lib.rs
index ff8ed03..b0854ba 100644
--- c/src/lib.rs
+++ i/src/lib.rs
@@ -8,156 +8,143 @@
 // - Isis Agora Lovecruft <isis@patternsinthevoid.net>

 //! ed25519 signatures and verification
 //!
 //! # Example
 //!
 //! Creating an ed25519 signature on a message is simple.
 //!
 //! First, we need to generate a `Keypair`, which includes both public and
 //! secret halves of an asymmetric key.  To do so, we need a cryptographically
-//! secure pseudorandom number generator (CSPRNG), and a hash function which
-//! has 512 bits of output.  For this example, we'll use the operating
-//! system's builtin PRNG and SHA-512 to generate a keypair:
+//! secure pseudorandom number generator (CSPRNG). For this example, we'll use
+//! the operating system's builtin PRNG:
 //!
 //! ```
 //! extern crate rand;
-//! extern crate sha2;
 //! extern crate ed25519_dalek;
 //!
-//! # #[cfg(all(feature = "std", feature = "sha2"))]
+//! # #[cfg(feature = "std")]
 //! # fn main() {
 //! use rand::Rng;
 //! use rand::OsRng;
-//! use sha2::Sha512;
 //! use ed25519_dalek::Keypair;
 //! use ed25519_dalek::Signature;
 //!
 //! let mut csprng: OsRng = OsRng::new().unwrap();
-//! let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng); // The `_` can be the type of `csprng`
+//! let keypair: Keypair = Keypair::generate(&mut csprng);
 //! # }
 //! #
-//! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))]
+//! # #[cfg(not(feature = "std"))]
 //! # fn main() { }
 //! ```
 //!
 //! We can now use this `keypair` to sign a message:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! let signature: Signature = keypair.sign(message);
 //! # }
 //! ```
 //!
 //! As well as to verify that this is, indeed, a valid signature on
 //! that `message`:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
-//! assert!(keypair.verify::<Sha512>(message, &signature).is_ok());
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
+//! assert!(keypair.verify(message, &signature).is_ok());
 //! # }
 //! ```
 //!
 //! Anyone else, given the `public` half of the `keypair` can also easily
 //! verify this signature:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::Keypair;
 //! # use ed25519_dalek::Signature;
 //! use ed25519_dalek::PublicKey;
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //!
 //! let public_key: PublicKey = keypair.public;
-//! assert!(public_key.verify::<Sha512>(message, &signature).is_ok());
+//! assert!(public_key.verify(message, &signature).is_ok());
 //! # }
 //! ```
 //!
 //! ## Serialisation
 //!
 //! `PublicKey`s, `SecretKey`s, `Keypair`s, and `Signature`s can be serialised
 //! into byte-arrays by calling `.to_bytes()`.  It's perfectly acceptible and
 //! safe to transfer and/or store those bytes.  (Of course, never transfer your
 //! secret key to anyone else, since they will only need the public key to
 //! verify your signatures!)
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
 //!
 //! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes();
 //! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes();
 //! let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair.to_bytes();
 //! let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature.to_bytes();
 //! # }
 //! ```
 //!
 //! And similarly, decoded from bytes with `::from_bytes()`:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError};
 //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
 //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> {
 //! # let mut csprng = thread_rng();
-//! # let keypair_orig: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature_orig: Signature = keypair_orig.sign::<Sha512>(message);
+//! # let keypair_orig: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature_orig: Signature = keypair_orig.sign(message);
 //! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes();
 //! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes();
 //! # let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair_orig.to_bytes();
 //! # let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature_orig.to_bytes();
 //! #
 //! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?;
 //! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?;
 //! let keypair:    Keypair   = Keypair::from_bytes(&keypair_bytes)?;
 //! let signature:  Signature = Signature::from_bytes(&signature_bytes)?;
 //! #
@@ -176,84 +163,80 @@
 //!
 //! ```bash
 //! $ cargo build --features="serde"
 //! ```
 //!
 //! They can be then serialised into any of the wire formats which serde supports.
 //! For example, using [bincode](https://github.com/TyOverby/bincode):
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # #[cfg(feature = "serde")]
 //! extern crate serde;
 //! # #[cfg(feature = "serde")]
 //! extern crate bincode;
 //!
 //! # #[cfg(feature = "serde")]
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! use bincode::{serialize, Infinite};
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
-//! # let verified: bool = public_key.verify::<Sha512>(message, &signature).is_ok();
+//! # let verified: bool = public_key.verify(message, &signature).is_ok();
 //!
 //! let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
 //! let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
 //! # }
 //! # #[cfg(not(feature = "serde"))]
 //! # fn main() {}
 //! ```
 //!
 //! After sending the `encoded_public_key` and `encoded_signature`, the
 //! recipient may deserialise them and verify:
 //!
 //! ```
 //! # extern crate rand;
-//! # extern crate sha2;
 //! # extern crate ed25519_dalek;
 //! # #[cfg(feature = "serde")]
 //! # extern crate serde;
 //! # #[cfg(feature = "serde")]
 //! # extern crate bincode;
 //! #
 //! # #[cfg(feature = "serde")]
 //! # fn main() {
 //! # use rand::Rng;
 //! # use rand::thread_rng;
-//! # use sha2::Sha512;
 //! # use ed25519_dalek::{Keypair, Signature, PublicKey};
 //! # use bincode::{serialize, Infinite};
 //! use bincode::{deserialize};
 //!
 //! # let mut csprng = thread_rng();
-//! # let keypair: Keypair = Keypair::generate::<Sha512, _>(&mut csprng);
-//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
-//! # let signature: Signature = keypair.sign::<Sha512>(message);
+//! # let keypair: Keypair = Keypair::generate(&mut csprng);
+//! let message: &[u8] = b"This is a test of the tsunami alert system.";
+//! # let signature: Signature = keypair.sign(message);
 //! # let public_key: PublicKey = keypair.public;
-//! # let verified: bool = public_key.verify::<Sha512>(message, &signature).is_ok();
+//! # let verified: bool = public_key.verify(message, &signature).is_ok();
 //! # let encoded_public_key: Vec<u8> = serialize(&public_key, Infinite).unwrap();
 //! # let encoded_signature: Vec<u8> = serialize(&signature, Infinite).unwrap();
 //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
 //! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
 //!
 //! # assert_eq!(public_key, decoded_public_key);
 //! # assert_eq!(signature, decoded_signature);
 //! #
-//! let verified: bool = decoded_public_key.verify::<Sha512>(&message, &decoded_signature).is_ok();
+//! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok();
 //!
 //! assert!(verified);
 //! # }
 //! # #[cfg(not(feature = "serde"))]
 //! # fn main() {}
 //! ```

 #![no_std]
 #![allow(unused_features)]
 #![deny(missing_docs)] // refuse to compile if documentation is missing
isislovecruft added a commit to isislovecruft/ed25519-dalek that referenced this issue Dec 30, 2018
This implements dalek-cryptography#64

You can still choose the "prehash" algorithm, as long as it has 64 bytes of
output.  Otherwise, everything is hardcoded to use sha2::Sha512.  To use a
different implementation you'll need a [patch.crates-io] section in cargo
config.
@isislovecruft
Copy link
Member Author

Implemented in #65 and included for 1.0.0-pre.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant