Skip to content

Commit b96d650

Browse files
committed
[WIP] signature v2.0.0-pre
This commit contains the first breaking changes to the `signature` crate made since its initial 1.0 stabilization. Planning for these changes occurred in #237. The following changes have been made: - The `Signature` trait has been renamed to `SignatureEncoding`. The `Signature` bound on `*Signer` and `*Verifier` traits has been removed, meaning there are no longer any mandatory trait bounds on the signature paramters at all. - The `AsRef<[u8]>` bound formerly found on the `Signature` crate has been replaced with an associated `Repr` type, inspired by the `group::GroupEncoding` trait. This means signature types no longer need to retain a serialized form, and can parse the bag-of-bytes representation to something more convenient, which is useful for e.g. batch verification. - The `std` feature is no longer enabled by default, which matches the other RustCrypto/traits crates. - The `derive-preview` and `hazmat-preview` features have been stabilized. - The former `Keypair` trait has been renamed to `KeypairRef`, and the signature generic parameter removed. A new `Keypair` trait has been added which returns an owned instance of the associated `VerifyingKey`, and a blanket impl of `Keypair` for `KeypairRef` has been added. This addresses the issues described in #1124.
1 parent 507349e commit b96d650

File tree

14 files changed

+162
-190
lines changed

14 files changed

+162
-190
lines changed

β€Ž.github/workflows/signature.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ jobs:
3737
override: true
3838
profile: minimal
3939
- run: cargo build --target ${{ matrix.target }} --release --no-default-features
40-
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive-preview
40+
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive
4141
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features digest-preview
42-
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features hazmat-preview
42+
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features hazmat
4343
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rand-preview
44+
- run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive,digest-preview,hazmat,rand-preview
4445

4546
minimal-versions:
4647
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
@@ -83,4 +84,4 @@ jobs:
8384
override: true
8485
profile: minimal
8586
- run: cargo test --release
86-
working-directory: signature/derive
87+
working-directory: signature/derive

β€Žsignature/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@ hex-literal = "0.3"
2222
sha2 = { version = "0.10", default-features = false }
2323

2424
[features]
25-
default = ["std"]
2625
std = []
2726

27+
derive = ["signature_derive"]
28+
2829
# Preview features are unstable and exempt from semver.
2930
# See https://docs.rs/signature/latest/signature/#unstable-features for more information.
30-
derive-preview = ["digest-preview", "signature_derive"]
3131
digest-preview = ["digest"]
32-
hazmat-preview = []
3332
rand-preview = ["rand_core"]
3433

3534
[package.metadata.docs.rs]

β€Žsignature/README.md

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# RustCrypto: Digital Signature Algorithms
1+
# [RustCrypto]: Digital Signature Algorithms
22

33
[![crate][crate-image]][crate-link]
44
[![Docs][docs-image]][docs-link]
@@ -8,14 +8,10 @@
88
[![Project Chat][chat-image]][chat-link]
99

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

13-
Used by the [`ecdsa`][2] and [`ed25519`][3] crates, with forthcoming support
14-
in the [`rsa`][4] crate.
15-
16-
See also the [Signatory][5] crate for trait wrappers for using these traits
17-
with many popular Rust cryptography crates, including `ed25519-dalek`, *ring*,
18-
`secp256k1-rs`, and `sodiumoxide`.
13+
Used by the [`dsa`], [`ecdsa`], [`ed25519`], and [`rsa`] crates maintained by
14+
the [RustCrypto] organization, as well as [`ed25519-dalek`].
1915

2016
[Documentation][docs-link]
2117

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

66-
[//]: # (general links)
62+
[//]: # (links)
6763

68-
[1]: https://en.wikipedia.org/wiki/Digital_signature
69-
[2]: https://github.com/RustCrypto/signatures/tree/master/ecdsa
70-
[3]: https://github.com/RustCrypto/signatures/tree/master/ed25519
71-
[4]: https://github.com/RustCrypto/RSA
72-
[5]: https://docs.rs/signatory
64+
[digital signatures]: https://en.wikipedia.org/wiki/Digital_signature
65+
[`dsa`]: https://github.com/RustCrypto/signatures/tree/master/dsa
66+
[`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa
67+
[`ed25519`]: https://github.com/RustCrypto/signatures/tree/master/ed25519
68+
[`ed25519-dalek`]: https://github.com/dalek-cryptography/ed25519-dalek
69+
[`rsa`]: https://github.com/RustCrypto/RSA

β€Žsignature/derive/src/lib.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ fn emit_digest_signer_impl(input: DeriveInput) -> TokenStream2 {
129129

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

168168
let mut params = DeriveParams::new(input);
169169
params.add_bound(&d_ident, parse_quote!(::signature::digest::Digest));
170-
params.add_bound(&s_ident, parse_quote!(::signature::Signature));
170+
params.add_param(&s_ident);
171171
params.add_bound(
172172
&Ident::new("Self", Span::call_site()),
173173
parse_quote!(::signature::hazmat::PrehashVerifier<#s_ident>),
@@ -235,14 +235,7 @@ impl DeriveParams {
235235
/// Add a generic parameter with the given bound.
236236
fn add_bound(&mut self, name: &Ident, bound: TraitBound) {
237237
if name != "Self" {
238-
self.impl_generics.push(TypeParam {
239-
attrs: vec![],
240-
ident: name.clone(),
241-
colon_token: None,
242-
bounds: Default::default(),
243-
eq_token: None,
244-
default: None,
245-
});
238+
self.add_param(name);
246239
}
247240

248241
let type_path = parse_quote!(#name);
@@ -261,6 +254,18 @@ impl DeriveParams {
261254
.predicates
262255
.push(WherePredicate::Type(predicate_type))
263256
}
257+
258+
/// Add a generic parameter without a bound.
259+
fn add_param(&mut self, name: &Ident) {
260+
self.impl_generics.push(TypeParam {
261+
attrs: vec![],
262+
ident: name.clone(),
263+
colon_token: None,
264+
bounds: Default::default(),
265+
eq_token: None,
266+
default: None,
267+
});
268+
}
264269
}
265270

266271
#[cfg(test)]
@@ -345,7 +350,6 @@ mod tests {
345350
impl<C: EllipticCurve, __D, __S> ::signature::DigestSigner<__D, __S> for MySigner<C>
346351
where
347352
__D: ::signature::digest::Digest,
348-
__S: ::signature::Signature,
349353
Self: ::signature::hazmat::PrehashSigner<__S>
350354
{
351355
fn try_sign_digest(&self, digest: __D) -> ::signature::Result<__S> {
@@ -374,7 +378,6 @@ mod tests {
374378
impl<C: EllipticCurve, __D, __S> ::signature::DigestVerifier<__D, __S> for MyVerifier<C>
375379
where
376380
__D: ::signature::digest::Digest,
377-
__S: ::signature::Signature,
378381
Self: ::signature::hazmat::PrehashVerifier<__S>
379382
{
380383
fn verify_digest(&self, digest: __D, signature: &__S) -> ::signature::Result<()> {

β€Žsignature/src/encoding.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Encoding support.
2+
3+
use crate::{Error, Result};
4+
5+
/// Support for decoding/encoding signatures as bytes.
6+
pub trait SignatureEncoding:
7+
Clone + Sized + for<'a> TryFrom<&'a [u8], Error = Error> + Into<Self::Repr>
8+
{
9+
/// Byte representation of a signature.
10+
type Repr: 'static + AsRef<[u8]> + AsMut<[u8]> + Clone + Default + Send + Sync;
11+
12+
/// Decode signature from its byte representation.
13+
fn from_bytes(bytes: &Self::Repr) -> Result<Self> {
14+
Self::try_from(bytes.as_ref())
15+
}
16+
17+
/// Encode signature as its byte representation.
18+
fn to_bytes(&self) -> Self::Repr {
19+
self.clone().into()
20+
}
21+
}

β€Žsignature/src/error.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ pub type Result<T> = core::result::Result<T, Error>;
2222
///
2323
/// [BB'06]: https://en.wikipedia.org/wiki/Daniel_Bleichenbacher
2424
#[derive(Default)]
25+
#[non_exhaustive]
2526
pub struct Error {
26-
/// Prevent from being instantiated as `Error {}` when the `std` feature
27-
/// is disabled
28-
_private: (),
29-
3027
/// Source of the error (if applicable).
3128
#[cfg(feature = "std")]
3229
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
@@ -50,7 +47,6 @@ impl Error {
5047
source: impl Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
5148
) -> Self {
5249
Self {
53-
_private: (),
5450
source: Some(source.into()),
5551
}
5652
}

β€Žsignature/src/hazmat.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
//! feature is semi-unstable and not subject to regular 1.x SemVer guarantees.
1111
//! However, any breaking changes will be accompanied with a minor version bump.
1212
13-
use crate::{Error, Signature};
13+
use crate::Error;
1414

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

1818
/// Sign the provided message prehash, returning a digital signature.
19-
pub trait PrehashSigner<S: Signature> {
19+
pub trait PrehashSigner<S> {
2020
/// Attempt to sign the given message digest, returning a digital signature
2121
/// on success, or an error if something went wrong.
2222
///
@@ -35,7 +35,7 @@ pub trait PrehashSigner<S: Signature> {
3535
/// Sign the provided message prehash using the provided external randomness source, returning a digital signature.
3636
#[cfg(feature = "rand-preview")]
3737
#[cfg_attr(docsrs, doc(cfg(feature = "rand-preview")))]
38-
pub trait RandomizedPrehashSigner<S: Signature> {
38+
pub trait RandomizedPrehashSigner<S> {
3939
/// Attempt to sign the given message digest, returning a digital signature
4040
/// on success, or an error if something went wrong.
4141
///
@@ -56,7 +56,7 @@ pub trait RandomizedPrehashSigner<S: Signature> {
5656
}
5757

5858
/// Verify the provided message prehash using `Self` (e.g. a public key)
59-
pub trait PrehashVerifier<S: Signature> {
59+
pub trait PrehashVerifier<S> {
6060
/// Use `Self` to verify that the provided signature for a given message
6161
/// `prehash` is authentic.
6262
///

β€Žsignature/src/keypair.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
//! Signing keypairs.
22
3-
use crate::Signature;
4-
53
/// Signing keypair with an associated verifying key.
64
///
75
/// This represents a type which holds both a signing key and a verifying key.
8-
pub trait Keypair<S: Signature>: AsRef<Self::VerifyingKey> {
6+
pub trait Keypair {
97
/// Verifying key type for this keypair.
10-
type VerifyingKey;
8+
type VerifyingKey: Clone;
119

1210
/// Get the verifying key which can verify signatures produced by the
1311
/// signing key portion of this keypair.
14-
fn verifying_key(&self) -> &Self::VerifyingKey {
15-
self.as_ref()
12+
fn verifying_key(&self) -> Self::VerifyingKey;
13+
}
14+
15+
/// Signing keypair with an associated verifying key.
16+
///
17+
/// This represents a type which holds both a signing key and a verifying key.
18+
pub trait KeypairRef: AsRef<Self::VerifyingKey> {
19+
/// Verifying key type for this keypair.
20+
type VerifyingKey: Clone;
21+
}
22+
23+
impl<K: KeypairRef> Keypair for K {
24+
type VerifyingKey = <Self as KeypairRef>::VerifyingKey;
25+
26+
fn verifying_key(&self) -> Self::VerifyingKey {
27+
self.as_ref().clone()
1628
}
1729
}

β€Žsignature/src/lib.rs

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,14 @@
4343
//! ## Implementation
4444
//!
4545
//! To accomplish the above goals, the [`Signer`] and [`Verifier`] traits
46-
//! provided by this are generic over a [`Signature`] return value, and use
47-
//! generic parameters rather than associated types. Notably, they use such
48-
//! a parameter for the return value, allowing it to be inferred by the type
49-
//! checker based on the desired signature type.
50-
//!
51-
//! The [`Signature`] trait is bounded on `AsRef<[u8]>`, enforcing that
52-
//! signature types are thin wrappers around a "bag-of-bytes"
53-
//! serialization. Inspiration for this approach comes from the Ed25519
54-
//! signature system, which was based on the observation that past
55-
//! systems were not prescriptive about how signatures should be represented
56-
//! on-the-wire, and that lead to a proliferation of different wire formats
57-
//! and confusion about which ones should be used. This crate aims to provide
58-
//! similar simplicity by minimizing the number of steps involved to obtain
59-
//! a serializable signature.
46+
//! provided by this are generic over a signature value, and use generic
47+
//! parameters rather than associated types. Notably, they use such a parameter
48+
//! for the return value, allowing it to be inferred by the type checker based
49+
//! on the desired signature type.
6050
//!
6151
//! ## Alternatives considered
6252
//!
63-
//! This crate is based on over two years of exploration of how to encapsulate
53+
//! This crate is based on many years of exploration of how to encapsulate
6454
//! digital signature systems in the most flexible, developer-friendly way.
6555
//! During that time many design alternatives were explored, tradeoffs
6656
//! compared, and ultimately the provided API was selected.
@@ -73,10 +63,7 @@
7363
//! - "Bag-of-bytes" serialization precludes signature providers from using
7464
//! their own internal representation of a signature, which can be helpful
7565
//! for many reasons (e.g. advanced signature system features like batch
76-
//! verification). Alternatively each provider could define its own signature
77-
//! type, using a marker trait to identify the particular signature algorithm,
78-
//! have `From` impls for converting to/from `[u8; N]`, and a marker trait
79-
//! for identifying a specific signature algorithm.
66+
//! verification).
8067
//! - Associated types, rather than generic parameters of traits, could allow
8168
//! more customization of the types used by a particular signature system,
8269
//! e.g. using custom error types.
@@ -121,7 +108,7 @@
121108
//! [`DigestSigner`] and [`DigestVerifier`], the `derive-preview` feature
122109
//! can be used to derive [`Signer`] and [`Verifier`] traits which prehash
123110
//! the input message using the [`PrehashSignature::Digest`] algorithm for
124-
//! a given [`Signature`] type. When the `derive-preview` feature is enabled
111+
//! a given signature type. When the `derive-preview` feature is enabled
125112
//! import the proc macros with `use signature::{Signer, Verifier}` and then
126113
//! add a `derive(Signer)` or `derive(Verifier)` attribute to the given
127114
//! digest signer/verifier type. Enabling this feature also enables `digest`
@@ -146,10 +133,10 @@
146133
#[cfg(feature = "std")]
147134
extern crate std;
148135

149-
#[cfg(all(feature = "signature_derive", not(feature = "derive-preview")))]
136+
#[cfg(all(feature = "signature_derive", not(feature = "derive")))]
150137
compile_error!(
151138
"The `signature_derive` feature should not be enabled directly. \
152-
Use the `derive-preview` feature instead."
139+
Use the `derive` feature instead."
153140
);
154141

155142
#[cfg(all(feature = "digest", not(feature = "digest-preview")))]
@@ -168,28 +155,28 @@ compile_error!(
168155
#[cfg_attr(docsrs, doc(cfg(feature = "hazmat-preview")))]
169156
pub mod hazmat;
170157

158+
mod encoding;
171159
mod error;
172160
mod keypair;
173-
mod signature;
174161
mod signer;
175162
mod verifier;
176163

177-
#[cfg(feature = "derive-preview")]
178-
#[cfg_attr(docsrs, doc(cfg(feature = "derive-preview")))]
164+
#[cfg(feature = "digest-preview")]
165+
mod prehash_signature;
166+
167+
pub use crate::{encoding::*, error::*, keypair::*, signer::*, verifier::*};
168+
169+
#[cfg(feature = "derive")]
170+
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
179171
pub use signature_derive::{Signer, Verifier};
180172

181-
#[cfg(all(feature = "derive-preview", feature = "digest-preview"))]
182-
#[cfg_attr(
183-
docsrs,
184-
doc(cfg(all(feature = "derive-preview", feature = "digest-preview")))
185-
)]
173+
#[cfg(all(feature = "derive", feature = "digest-preview"))]
174+
#[cfg_attr(docsrs, doc(cfg(all(feature = "derive", feature = "digest-preview"))))]
186175
pub use signature_derive::{DigestSigner, DigestVerifier};
187176

188177
#[cfg(feature = "digest-preview")]
189-
pub use digest;
178+
pub use {crate::prehash_signature::*, digest};
190179

191180
#[cfg(feature = "rand-preview")]
192181
#[cfg_attr(docsrs, doc(cfg(feature = "rand-preview")))]
193182
pub use rand_core;
194-
195-
pub use crate::{error::*, keypair::*, signature::*, signer::*, verifier::*};

β€Žsignature/src/prehash_signature.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//! `PrehashSignature` trait.
2+
3+
/// For intra-doc link resolution.
4+
#[allow(unused_imports)]
5+
use crate::{
6+
signer::{DigestSigner, Signer},
7+
verifier::{DigestVerifier, Verifier},
8+
};
9+
10+
/// Marker trait for `Signature` types computable as `𝐒(𝐇(π’Ž))`
11+
/// i.e. ones which prehash a message to be signed as `𝐇(π’Ž)`
12+
///
13+
/// Where:
14+
///
15+
/// - `𝐒`: signature algorithm
16+
/// - `𝐇`: hash (a.k.a. digest) function
17+
/// - `π’Ž`: message
18+
///
19+
/// This approach is relatively common in signature schemes based on the
20+
/// [Fiat-Shamir heuristic].
21+
///
22+
/// For signature types that implement this trait, when the `derive-preview`
23+
/// Cargo feature is enabled a custom derive for [`Signer`] is available for any
24+
/// types that impl [`DigestSigner`], and likewise for deriving [`Verifier`] for
25+
/// types which impl [`DigestVerifier`].
26+
///
27+
/// [Fiat-Shamir heuristic]: https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic
28+
#[cfg_attr(docsrs, doc(cfg(feature = "digest")))]
29+
pub trait PrehashSignature {
30+
/// Preferred `Digest` algorithm to use when computing this signature type.
31+
type Digest: digest::Digest;
32+
}

0 commit comments

Comments
Β (0)