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

signature v2.0.0-pre #1141

Merged
merged 3 commits into from
Oct 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/signature.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ jobs:
override: true
profile: minimal
- run: cargo build --target ${{ matrix.target }} --release --no-default-features
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive-preview
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features digest-preview
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features hazmat-preview
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rand-preview
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive,digest-preview,rand-preview

minimal-versions:
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
Expand Down Expand Up @@ -83,4 +83,4 @@ jobs:
override: true
profile: minimal
- run: cargo test --release
working-directory: signature/derive
working-directory: signature/derive
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crypto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "crypto"
version = "0.4.0" # Also update html_root_url in lib.rs when bumping this
version = "0.5.0-pre" # Also update html_root_url in lib.rs when bumping this
description = """
Resources for building cryptosystems in Rust using the RustCrypto project's ecosystem.
"""
Expand All @@ -23,7 +23,7 @@ cipher = { version = "0.4", optional = true }
digest = { version = "0.10", optional = true, features = ["mac"] }
elliptic-curve = { version = "0.12", optional = true, path = "../elliptic-curve" }
password-hash = { version = "0.4", optional = true, path = "../password-hash" }
signature = { version = "1.5", optional = true, default-features = false, path = "../signature" }
signature = { version = "=2.0.0-pre", optional = true, default-features = false, path = "../signature" }
universal-hash = { version = "0.5", optional = true, path = "../universal-hash" }

[features]
Expand Down
10 changes: 4 additions & 6 deletions signature/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "signature"
description = "Traits for cryptographic signature algorithms (e.g. ECDSA, Ed25519)"
version = "1.6.4"
version = "2.0.0-pre"
authors = ["RustCrypto Developers"]
license = "Apache-2.0 OR MIT"
documentation = "https://docs.rs/signature"
Expand All @@ -15,21 +15,19 @@ categories = ["cryptography", "no-std"]
[dependencies]
digest = { version = "0.10.3", optional = true, default-features = false }
rand_core = { version = "0.6", optional = true, default-features = false }
signature_derive = { version = "=1.0.0-pre.7", optional = true, path = "derive" }
derive = { package = "signature_derive", version = "=1.0.0-pre.7", optional = true, path = "derive" }

[dev-dependencies]
hex-literal = "0.3"
sha2 = { version = "0.10", default-features = false }

[features]
default = ["std"]
std = []
alloc = []
std = ["alloc"]

# Preview features are unstable and exempt from semver.
# See https://docs.rs/signature/latest/signature/#unstable-features for more information.
derive-preview = ["digest-preview", "signature_derive"]
digest-preview = ["digest"]
hazmat-preview = []
rand-preview = ["rand_core"]

[package.metadata.docs.rs]
Expand Down
25 changes: 11 additions & 14 deletions signature/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# RustCrypto: Digital Signature Algorithms
# [RustCrypto]: Digital Signature Algorithms

[![crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
Expand All @@ -8,14 +8,10 @@
[![Project Chat][chat-image]][chat-link]

This crate contains traits which provide generic, object-safe APIs for
generating and verifying [digital signatures][1].
generating and verifying [digital signatures].

Used by the [`ecdsa`][2] and [`ed25519`][3] crates, with forthcoming support
in the [`rsa`][4] crate.

See also the [Signatory][5] crate for trait wrappers for using these traits
with many popular Rust cryptography crates, including `ed25519-dalek`, *ring*,
`secp256k1-rs`, and `sodiumoxide`.
Used by the [`dsa`], [`ecdsa`], [`ed25519`], and [`rsa`] crates maintained by
the [RustCrypto] organization, as well as [`ed25519-dalek`].

[Documentation][docs-link]

Expand Down Expand Up @@ -63,10 +59,11 @@ dual licensed as above, without any additional terms or conditions.
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260048-signatures

[//]: # (general links)
[//]: # (links)

[1]: https://en.wikipedia.org/wiki/Digital_signature
[2]: https://github.com/RustCrypto/signatures/tree/master/ecdsa
[3]: https://github.com/RustCrypto/signatures/tree/master/ed25519
[4]: https://github.com/RustCrypto/RSA
[5]: https://docs.rs/signatory
[digital signatures]: https://en.wikipedia.org/wiki/Digital_signature
[`dsa`]: https://github.com/RustCrypto/signatures/tree/master/dsa
[`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa
[`ed25519`]: https://github.com/RustCrypto/signatures/tree/master/ed25519
[`ed25519-dalek`]: https://github.com/dalek-cryptography/ed25519-dalek
[`rsa`]: https://github.com/RustCrypto/RSA
2 changes: 1 addition & 1 deletion signature/async/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ rust-version = "1.56"

[dependencies]
async-trait = "0.1.9"
signature = { version = "1.6", path = ".." }
signature = { version = "=2.0.0-pre", path = ".." }

[features]
digest = ["signature/digest-preview"]
Expand Down
37 changes: 5 additions & 32 deletions signature/async/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]

pub use signature::{self, Error, Signature};
pub use signature::{self, Error};

#[cfg(feature = "digest")]
pub use signature::digest::{self, Digest};
Expand All @@ -22,7 +22,7 @@ use async_trait::async_trait;
pub trait AsyncSigner<S>
where
Self: Send + Sync,
S: Signature + Send + 'static,
S: Send + 'static,
{
/// Attempt to sign the given message, returning a digital signature on
/// success, or an error if something went wrong.
Expand All @@ -35,7 +35,7 @@ where
#[async_trait]
impl<S, T> AsyncSigner<S> for T
where
S: Signature + Send + 'static,
S: Send + 'static,
T: signature::Signer<S> + Send + Sync,
{
async fn sign_async(&self, msg: &[u8]) -> Result<S, Error> {
Expand All @@ -53,7 +53,7 @@ pub trait AsyncDigestSigner<D, S>
where
Self: Send + Sync,
D: Digest + Send + 'static,
S: Signature + 'static,
S: 'static,
{
/// Attempt to sign the given prehashed message [`Digest`], returning a
/// digital signature on success, or an error if something went wrong.
Expand All @@ -65,37 +65,10 @@ where
impl<D, S, T> AsyncDigestSigner<D, S> for T
where
D: Digest + Send + 'static,
S: Signature + Send + 'static,
S: Send + 'static,
T: signature::DigestSigner<D, S> + Send + Sync,
{
async fn sign_digest_async(&self, digest: D) -> Result<S, Error> {
self.try_sign_digest(digest)
}
}

/// Keypair with async signer component and an associated verifying key.
///
/// This represents a type which holds both an async signing key and a verifying key.
#[deprecated(since = "0.2.1", note = "use signature::Keypair instead")]
pub trait AsyncKeypair<S>: AsRef<Self::VerifyingKey>
where
S: Signature + Send + 'static,
{
/// Verifying key type for this keypair.
type VerifyingKey;

/// Get the verifying key which can verify signatures produced by the
/// signing key portion of this keypair.
fn verifying_key(&self) -> &Self::VerifyingKey {
self.as_ref()
}
}

#[allow(deprecated)]
impl<S, T> AsyncKeypair<S> for T
where
S: Signature + Send + 'static,
T: signature::Keypair<S> + Send + Sync,
{
type VerifyingKey = <T as signature::Keypair<S>>::VerifyingKey;
}
27 changes: 15 additions & 12 deletions signature/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ fn emit_digest_signer_impl(input: DeriveInput) -> TokenStream2 {

let mut params = DeriveParams::new(input);
params.add_bound(&d_ident, parse_quote!(::signature::digest::Digest));
params.add_bound(&s_ident, parse_quote!(::signature::Signature));
params.add_param(&s_ident);
params.add_bound(
&Ident::new("Self", Span::call_site()),
parse_quote!(::signature::hazmat::PrehashSigner<#s_ident>),
Expand Down Expand Up @@ -167,7 +167,7 @@ fn emit_digest_verifier_impl(input: DeriveInput) -> TokenStream2 {

let mut params = DeriveParams::new(input);
params.add_bound(&d_ident, parse_quote!(::signature::digest::Digest));
params.add_bound(&s_ident, parse_quote!(::signature::Signature));
params.add_param(&s_ident);
params.add_bound(
&Ident::new("Self", Span::call_site()),
parse_quote!(::signature::hazmat::PrehashVerifier<#s_ident>),
Expand Down Expand Up @@ -235,14 +235,7 @@ impl DeriveParams {
/// Add a generic parameter with the given bound.
fn add_bound(&mut self, name: &Ident, bound: TraitBound) {
if name != "Self" {
self.impl_generics.push(TypeParam {
attrs: vec![],
ident: name.clone(),
colon_token: None,
bounds: Default::default(),
eq_token: None,
default: None,
});
self.add_param(name);
}

let type_path = parse_quote!(#name);
Expand All @@ -261,6 +254,18 @@ impl DeriveParams {
.predicates
.push(WherePredicate::Type(predicate_type))
}

/// Add a generic parameter without a bound.
fn add_param(&mut self, name: &Ident) {
self.impl_generics.push(TypeParam {
attrs: vec![],
ident: name.clone(),
colon_token: None,
bounds: Default::default(),
eq_token: None,
default: None,
});
}
}

#[cfg(test)]
Expand Down Expand Up @@ -345,7 +350,6 @@ mod tests {
impl<C: EllipticCurve, __D, __S> ::signature::DigestSigner<__D, __S> for MySigner<C>
where
__D: ::signature::digest::Digest,
__S: ::signature::Signature,
Self: ::signature::hazmat::PrehashSigner<__S>
{
fn try_sign_digest(&self, digest: __D) -> ::signature::Result<__S> {
Expand Down Expand Up @@ -374,7 +378,6 @@ mod tests {
impl<C: EllipticCurve, __D, __S> ::signature::DigestVerifier<__D, __S> for MyVerifier<C>
where
__D: ::signature::digest::Digest,
__S: ::signature::Signature,
Self: ::signature::hazmat::PrehashVerifier<__S>
{
fn verify_digest(&self, digest: __D, signature: &__S) -> ::signature::Result<()> {
Expand Down
38 changes: 38 additions & 0 deletions signature/src/encoding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Encoding support.
use crate::{Error, Result};

#[cfg(feature = "alloc")]
use alloc::{boxed::Box, vec::Vec};

/// Support for decoding/encoding signatures as bytes.
pub trait SignatureEncoding:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the main argument here that there's no inherent need for someone with access to an S: Signer to be able to (de)serialize the resulting signatures? I'd buy that argument. Are there examples in the wild?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is largely a reaction (perhaps an overreaction) to mandatory trait bounds around the Signature trait in the v1.0 signature crate being too restrictive and preventing some things that would otherwise be valid. Although debatably the AsRef<[u8]> one was too onerous.

As far as a real-world example of something eliminating the bounds enables, the main thing is probably a heapless core implementation with an alloc-dependent SignatureEncoding impl:

https://github.com/RustCrypto/signatures/pull/562/files#diff-23f3fe37b15706957a041307578d2433204986a9eb42dc8d7c4126dcaf9266f1R226-R239

In this case, it's a variable-width ASN.1 DER-encoded type, which knows how to serialize itself into a buffer on heapless platforms, but when the heap is available, it's nice to be able to serialize it into a heap-backed structure (in this case Box<[u8]>)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. In the above case, couldn't SignatureEncoding be implemented without the feature gate? The def simply won't contain the to_vec part if alloc isn't set. Or is the trait simply not useful in that case (for this particular crate)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SignatureEncoding::Repr in that example is an alloc::boxed::Box<[u8]>, so no, it cannot be defined without the alloc feature enabled.

Clone + Sized + for<'a> TryFrom<&'a [u8], Error = Error> + Into<Self::Repr>
{
/// Byte representation of a signature.
type Repr: 'static + AsRef<[u8]> + AsMut<[u8]> + Clone + Default + Send + Sync;

/// Decode signature from its byte representation.
fn from_bytes(bytes: &Self::Repr) -> Result<Self> {
Self::try_from(bytes.as_ref())
}

/// Encode signature as its byte representation.
fn to_bytes(&self) -> Self::Repr {
self.clone().into()
}

/// Encode signature as a byte vector.
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
fn to_vec(&self) -> Vec<u8> {
self.to_bytes().as_ref().to_vec()
}

/// Encode the signature as a boxed byte slice.
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
fn to_boxed_slice(&self) -> Box<[u8]> {
tarcieri marked this conversation as resolved.
Show resolved Hide resolved
self.to_vec().into_boxed_slice()
}
}
6 changes: 1 addition & 5 deletions signature/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@ pub type Result<T> = core::result::Result<T, Error>;
///
/// [BB'06]: https://en.wikipedia.org/wiki/Daniel_Bleichenbacher
#[derive(Default)]
#[non_exhaustive]
pub struct Error {
/// Prevent from being instantiated as `Error {}` when the `std` feature
/// is disabled
_private: (),

/// Source of the error (if applicable).
#[cfg(feature = "std")]
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
Expand All @@ -50,7 +47,6 @@ impl Error {
source: impl Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
) -> Self {
Self {
_private: (),
source: Some(source.into()),
}
}
Expand Down
8 changes: 4 additions & 4 deletions signature/src/hazmat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
//! feature is semi-unstable and not subject to regular 1.x SemVer guarantees.
//! However, any breaking changes will be accompanied with a minor version bump.
use crate::{Error, Signature};
use crate::Error;

#[cfg(feature = "rand-preview")]
use crate::rand_core::{CryptoRng, RngCore};

/// Sign the provided message prehash, returning a digital signature.
pub trait PrehashSigner<S: Signature> {
pub trait PrehashSigner<S> {
/// Attempt to sign the given message digest, returning a digital signature
/// on success, or an error if something went wrong.
///
Expand All @@ -35,7 +35,7 @@ pub trait PrehashSigner<S: Signature> {
/// Sign the provided message prehash using the provided external randomness source, returning a digital signature.
#[cfg(feature = "rand-preview")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand-preview")))]
pub trait RandomizedPrehashSigner<S: Signature> {
pub trait RandomizedPrehashSigner<S> {
/// Attempt to sign the given message digest, returning a digital signature
/// on success, or an error if something went wrong.
///
Expand All @@ -56,7 +56,7 @@ pub trait RandomizedPrehashSigner<S: Signature> {
}

/// Verify the provided message prehash using `Self` (e.g. a public key)
pub trait PrehashVerifier<S: Signature> {
pub trait PrehashVerifier<S> {
/// Use `Self` to verify that the provided signature for a given message
/// `prehash` is authentic.
///
Expand Down
Loading