Use ed25519 + signature interop crates#102
Use ed25519 + signature interop crates#102tarcieri wants to merge 1 commit intodalek-cryptography:masterfrom
ed25519 + signature interop crates#102Conversation
|
I think this still is a bit rough around the edges. This is partly due to the crates being named I'll try to leave some line notes about the parts I don't like. Ideally I think we could get rid of the existing (private) |
| @@ -9,49 +9,6 @@ | |||
|
|
|||
| //! Errors which may occur when parsing keys and/or signatures to or from wire formats. | |||
There was a problem hiding this comment.
This is perhaps the most invasive change in the current implementation: it eliminates the InternalError type entirely, and uses the opaque signature::Error type as SignatureError. Additionally, it drops failure, and uses the equivalent std::error::Error trait when available.
It's still possible to support InternalError using the current signature crate via its Error::source feature, but only when std is enabled:
However, as noted in the docs above, the signature crate discourages this to avoid sidechannel leakage that might allow the attacker to either recover a private key or forge a signature.
If you'd prefer to keep the InternalError type, I can use Error::from_source to capture it, and expose it as Error::source, but only when the std feature is enabled (since it uses Box to store it internally, and exposes it through the std::error::Error trait)
| pub use ed25519_crate::{Signature, signature::Signature as SignatureTrait}; | ||
|
|
||
| /// Extension trait for the `Signature` type providing access to the | ||
| /// `R` and `s` components of the signature. |
There was a problem hiding this comment.
Since the ed25519 crate provides the ed25519::Signature type (which internally is a 64-byte "octet string"), I opted to define an extension trait to provide the previous behavior. Let me know what you think of this approach. Alternatively I think this code could be factored to the relevant call sites.
| } | ||
| } | ||
|
|
||
| impl Signer<Signature> for Keypair { |
There was a problem hiding this comment.
This is the main interop trait for signing. It's generic around the return value (ed25519::Signature, in this case)
|
|
||
| impl Signer<Signature> for Keypair { | ||
| /// Sign a message with this keypair's secret key. | ||
| fn try_sign(&self, message: &[u8]) -> Result<Signature, SignatureError> { |
There was a problem hiding this comment.
This trait provides an infallible sign method impl'd in terms of try_sign, which exists to support e.g. HSMs which can have communication errors while signing.
In the case of this library, since signing is always infallible, it just returns Ok
| } | ||
| } | ||
|
|
||
| impl Verifier<Signature> for Keypair { |
There was a problem hiding this comment.
This is the main interop trait for signature verification
| } | ||
| } | ||
|
|
||
| #[cfg(feature = "serde")] |
There was a problem hiding this comment.
The ed25519 crate provides a serde feature, but it uses the bag-of-bytes representation of a signature, and needed some more invasive changes which I didn't complete as part of the initial PR.
|
Looks like the tests are failing due to |
| #[derive(Copy, Eq, PartialEq)] | ||
| pub struct Signature { | ||
| // Re-export the `ed25519` crate's Signature type | ||
| pub use ed25519_crate::{Signature, signature::Signature as SignatureTrait}; |
There was a problem hiding this comment.
I really dislike naming a trait *Trait, but it was necessary here to avoid a naming collision (partially exacerbated by the pre-2018 module system).
Fortunately importing it is rarely needed: the only methods the itself trait provides are from_bytes and as_slice, with equivalent functionality available through TryFrom<&[u8]> and AsRef<[u8]> impls. Otherwise its main function is to provide a set of other trait bounds.
Ideally I think the signature module could be eliminated and the signature crate publicly re-exported at the toplevel. That would allow this trait to be accessed as:
use ed25519_dalek::signature::Signature as _;(I'm all ears on suggested alternative naming if that still seems confusing)
There was a problem hiding this comment.
Put the trait in a src/signature/prelude.rs maybe? Although I personally find that "prelude" naming pretentious, and have "traits" submodules usually. In code this reads as Signature: traits::Signature, in docs sometimes as just Signature: Signature.
|
I think instead of forcing the "bag of bytes" on EDIT: see #80 for a lengthy discussion on the mutual merits. |
The `ed25519` crate and the `signature` crates provide trait-based interoperability between Ed25519 libraries: https://github.com/RustCrypto/signatures This commit integrates the `ed25519::Signature` type, and changes the existing `sign` and `verify` methods to use the `Signer` and `Verifier` traits from the `signature` crate. Additionally, it replaces the current error types with an opaque one from the `signature` crate. This has the drawback of requiring the `Signer` and `Verifier` traits are in scope in order to create signatures, but the benefit of interoperable support for other Ed25519 signers and verifiers. Presently there are a number of these provided through the Signatory framework, along with support for HSM-backed Ed25519 signatures in the `yubihsm` crate: - https://github.com/tendermint/signatory - https://github.com/tendermint/yubihsm-rs
|
Rebased off Looks like there's still one remaining bug with |
|
|
||
| #[cfg(not(feature = "legacy_compatibility"))] | ||
| #[inline(always)] | ||
| fn check_scalar(bytes: [u8; 32]) -> Result<Scalar, SignatureError> { |
There was a problem hiding this comment.
This was unfortunate to lose in the rebase, and perhaps there's something we can still do yet to retain it, but note that the check_scalar check above (for the highest 3 bits being unset) was adapted into the ed25519 crate:
|
I'm not really happy with the state of this PR after rebasing, as it seems a lot of recent work was lost in the rebase. So I think I'll redo it from scratch, and try to find a less invasive way of implementing it which preserves all of the current functionality. |
|
Opened a new, less invasive version of this PR in #124 |
The
ed25519crate and thesignaturecrates provide trait-based interoperability between Ed25519 libraries:https://github.com/RustCrypto/signatures
This commit integrates the
ed25519::Signaturetype, and changes the existingsignandverifymethods to use theSignerandVerifiertraits from thesignaturecrate. Additionally, it replaces the current error types with an opaque one from thesignaturecrate.This has the drawback of requiring the
SignerandVerifiertraits are in scope in order to create signatures, but the benefit of interoperable support for other Ed25519 signers and verifiers. Presentlythere are a number of these provided through the Signatory framework, along with support for HSM-backed Ed25519 signatures in the
yubihsmcrate: