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: design documentation #72

Merged
merged 1 commit into from
Mar 8, 2020
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Collection of traits which describe functionality of cryptographic primitives.
## Crates
| Name | Crates.io | Documentation |
| ------- | :---------:| :-------------:|
| [`aead`](hhttps://en.wikipedia.org/wiki/Authenticated_encryption)| [![crates.io](https://img.shields.io/crates/v/aead.svg)](https://crates.io/crates/aead) | [![Documentation](https://docs.rs/aead/badge.svg)](https://docs.rs/aead) |
| [`aead`](https://en.wikipedia.org/wiki/Authenticated_encryption)| [![crates.io](https://img.shields.io/crates/v/aead.svg)](https://crates.io/crates/aead) | [![Documentation](https://docs.rs/aead/badge.svg)](https://docs.rs/aead) |
| [`block-cipher-trait`](https://en.wikipedia.org/wiki/Block_cipher)| [![crates.io](https://img.shields.io/crates/v/block-cipher-trait.svg)](https://crates.io/crates/block-cipher-trait) | [![Documentation](https://docs.rs/block-cipher-trait/badge.svg)](https://docs.rs/block-cipher-trait) |
| [`crypto-mac`](https://en.wikipedia.org/wiki/Message_authentication_code) | [![crates.io](https://img.shields.io/crates/v/crypto-mac.svg)](https://crates.io/crates/crypto-mac) | [![Documentation](https://docs.rs/crypto-mac/badge.svg)](https://docs.rs/crypto-mac) |
| [`digest`](https://en.wikipedia.org/wiki/Cryptographic_hash_function) | [![crates.io](https://img.shields.io/crates/v/digest.svg)](https://crates.io/crates/digest) | [![Documentation](https://docs.rs/digest/badge.svg)](https://docs.rs/digest) |
Expand Down
2 changes: 1 addition & 1 deletion signature/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# `signature` crate
# RustCrypto: `signature` crate

[![crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
Expand Down
1 change: 1 addition & 0 deletions signature/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl Error {
/// cases are for propagating errors related to external signers, e.g.
/// communication/authentication errors with HSMs, KMS, etc.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn from_source(source: impl Into<BoxError>) -> Self {
Self {
source: Some(source.into()),
Expand Down
131 changes: 119 additions & 12 deletions signature/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,137 @@
//! RustCrypto: `signature` crate.
//!
//! Traits which provide generic, object-safe APIs for generating and verifying
//! digital signatures, which provide message authentication using public-key
//! cryptography.
//! digital signatures: message authentication using public-key cryptography.
//!
//! ## Minimum Supported Rust Version
//!
//! Rust **1.34** or higher.
//! Rust **1.36** or higher.
//!
//! Minimum supported Rust version can be changed in the future, but it will be
//! done with a minor version bump.
//! Minimum supported Rust version may be changed in the future, but such
//! changes will be accompanied with a minor version bump.
//!
//! ## SemVer Policy
//! ## SemVer policy
//!
//! - All on-by-default features of this library are covered by SemVer
//! - MSRV is considered exempt from SemVer as noted above
//! - The off-by-default features `derive-preview` and `digest-preview` are
//! unstable "preview" features which are also considered exempt from SemVer.
//! Breaking changes to these features will, like MSRV, be done with a minor
//! version bump.
//! - Off-by-default features ending in `*-preview` (e.g. `derive-preview`,
//! `digest-preview`) are unstable "preview" features which are also
//! considered exempt from SemVer (typically because they rely on pre-1.0
//! crates as dependencies). However, breaking changes to these features
//! will, like MSRV, also be accompanied by a minor version bump.
//!
//! # Design
//!
//! This crate provides a common set of traits for signing and verifying
//! digital signatures intended to be implemented by libraries which produce
//! or contain implementations of digital signature algorithms, and used by
//! libraries which want to produce or verify digital signatures while
//! generically supporting any compatible backend.
//!
//! ## Goals
//!
//! The traits provided by this crate were designed with the following goals
//! in mind:
//!
//! - Provide an easy-to-use, misuse resistant API optimized for consumers
//! (as opposed to implementers) of its traits.
//! - Support common type-safe wrappers around "bag-of-bytes" representations
//! which can be directly parsed from or written to the "wire".
//! - Expose a trait/object-safe API where signers/verifiers spanning multiple
//! homogeneous provider implementations can be seamlessly leveraged together
//! in the same logical "keyring" so long as they operate on the same
//! underlying signature type.
//! - Allow one provider type to potentially implement support (including
//! being generic over) several signature types.
//! - Keep signature algorithm customizations / "knobs" out-of-band from the
//! signing/verification APIs, ideally pushing such concerns into the type
//! system so that algorithm mismatches are caught as type errors.
//! - Opaque error type which minimizes information leaked from crxyptographic
//! failures, as "rich" error types in these scenarios are often a source
//! of sidechannel information for attackers (e.g. [BB'06])
//!
//! [BB'06]: https://en.wikipedia.org/wiki/Daniel_Bleichenbacher
//!
//! # Implementation
//!
//! To accomplish the above goals, the [`Signer`] and [`Verifier`] traits
//! provided by this are generic over a [`Signature`] return value, and use
//! generic parameters rather than associated types. Notably, they use such
//! a parameter for the return value, allowing it to be inferred by the type
//! checker based on the desired signature type.
//!
//! The [`Signature`] trait is bounded on `AsRef<[u8]>`, enforcing that
//! signature types are thin wrappers around a "bag-of-bytes"
//! serialization. Inspiration for this approach comes from the Ed25519
//! signature system, which was based on the observation that past
//! systems were not prescriptive about how signatures should be represented
//! on-the-wire, and that lead to a proliferation of different wire formats
//! and confusion about which ones should be used. This crate aims to provide
//! similar simplicity by minimizing the number of steps involved to obtain
//! a serializable signature.
//!
//! # Alternatives considered
//!
//! This crate is based on over two years of exploration of how to encapsulate
//! digital signature systems in the most flexible, developer-friendly way.
//! During that time many design alternatives were explored, tradeoffs
//! compared, and ultimately the provided API was selected.
//!
//! The tradeoffs made in this API have all been to improve simplicity,
//! ergonomics, type safety, and flexibility for *consumers* of the traits.
//! At times, this has come at a cost to implementers. Below are some concerns
//! we are cognizant of which were considered in the design of the API:
//!
//! - "Bag-of-bytes" serialization precludes signature providers from using
//! their own internal representation of a signature, which can be helpful
//! for many reasons (e.g. advanced signature system features like batch
//! verification). Alternatively each provider could define its own signature
//! type, using a marker trait to identify the particular signature algorithm,
//! have `From` impls for converting to/from `[u8; N]`, and a marker trait
//! for identifying a specific signature algorithm.
//! - Associated types, rather than generic parameters of traits, could allow
//! more customization of the types used by a particular signature system,
//! e.g. using custom error types.
//!
//! It may still make sense to continue to explore the above tradeoffs, but
//! with a *new* set of traits which are intended to be implementor-friendly,
//! rather than consumer friendly. The existing [`Signer`] and [`Verifier`]
//! traits could have blanket impls for the "provider-friendly" traits.
//! However, as noted above this is a design space easily explored after
//! stabilizing the consumer-oriented traits, and thus we consider these
//! more important.
//!
//! That said, below are some caveats of trying to design such traits, and
//! why we haven't actively pursued them:
//!
//! - Generics in the return position are already used to select which trait
//! impl to use, i.e. for a particular signature algorithm/system. Avoiding
//! a unified, concrete signature type adds another dimension to complexity
//! and compiler errors, and in our experience makes them unsuitable for this
//! sort of API. We believe such an API is the natural one for signature
//! systems, reflecting the natural way they are written absent a trait.
//! - Associated types preclude multiple (or generic) implementations of the
//! same trait. These parameters are common in signature systems, notably
//! ones which support different digest algorithms.
//! - Digital signatures are almost always larger than the present 32-entry
//! trait impl limitation on array types, which complicates trait signatures
//! for these types (particularly things like `From` or `Borrow` bounds).
//! This may be more interesting to explore after const generics.
//!
//!

#![no_std]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png",
html_root_url = "https://docs.rs/signature/1.0.0-pre.1"
)]
#![forbid(unsafe_code)]
#![warn(
missing_docs,
rust_2018_idioms,
unused_qualifications,
intra_doc_link_resolution_failure
)]

#[cfg(feature = "std")]
#[macro_use]
Expand Down
21 changes: 17 additions & 4 deletions signature/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
use crate::error::Error;
use core::fmt::Debug;

/// For intra-doc link resolution
#[cfg(feature = "digest-preview")]
#[allow(unused_imports)]
use crate::{
signer::{DigestSigner, Signer},
verifier::{DigestVerifier, Verifier},
};

/// Trait impl'd by concrete types that represent digital signatures
pub trait Signature: AsRef<[u8]> + Debug + Sized {
/// Parse a signature from its byte representation
Expand All @@ -20,11 +28,16 @@ pub trait Signature: AsRef<[u8]> + Debug + Sized {
/// - `H`: hash (a.k.a. digest) function
/// - `m`: message
///
/// i.e. a traditional application of the [Fiat-Shamir heuristic].
///
/// For signature types that implement this trait, when the `derive-preview`
/// Cargo feature is enabled a custom derive for `Signer` is available for any
/// types that impl `DigestSigner`, and likewise for deriving `Verifier` for
/// types which impl `DigestVerifier`.
#[cfg(feature = "digest")]
/// Cargo feature is enabled a custom derive for [`Signer`] is available for any
/// types that impl [`DigestSigner`], and likewise for deriving [`Verifier`] for
/// types which impl [`DigestVerifier`].
///
/// [Fiat-Shamir heuristic]: https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic
#[cfg(feature = "digest-preview")]
#[cfg_attr(docsrs, doc(cfg(feature = "digest-preview")))]
pub trait DigestSignature: Signature {
/// Preferred `Digest` algorithm to use when computing this signature type.
type Digest: digest::Digest;
Expand Down
20 changes: 18 additions & 2 deletions signature/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,25 @@ pub trait Signer<S: Signature> {

/// Sign the given prehashed message `Digest` using `Self`.
///
/// This trait is only available when the `digest-preview` cargo feature is
/// enabled.
/// ## Notes
///
/// This trait is primarily intended for signature algorithms based on the
/// [Fiat-Shamir heuristic], a method for converting an interactive
/// challenge/response-based proof-of-knowledge protocol into an offline
/// digital signature through the use of a random oracle, i.e. a digest
/// function.
///
/// The security of such protocols critically rests upon the inability of
/// an attacker to solve for the output of the random oracle, as generally
/// otherwise such signature algorithms are a system of linear equations and
/// therefore doing so would allow the attacker to trivially forge signatures.
///
/// To prevent misuse which would potentially allow this to be possible, this
/// API accepts a [`Digest`] instance, rather than a raw digest value.
///
/// [Fiat-Shamir heuristic]: https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic
#[cfg(feature = "digest-preview")]
#[cfg_attr(docsrs, doc(cfg(feature = "digest-preview")))]
pub trait DigestSigner<D, S>
where
D: Digest,
Expand Down
24 changes: 17 additions & 7 deletions signature/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,25 @@ pub trait Verifier<S: Signature> {
/// Verify the provided signature for the given prehashed message `Digest`
/// is authentic.
///
/// This trait is only available when the `digest-preview` cargo feature is
/// enabled.
/// ## Notes
///
/// It accepts a [`Digest`] instance, as opposed to a raw digest byte array,
/// as the security of signature algorithms built on hash functions often
/// depends critically on the input being a random oracle as opposed to a
/// value an attacker can choose and solve for. This is enforced at the API
/// level by taking a [`Digest`] instance in order to better resist misuse.
/// This trait is primarily intended for signature algorithms based on the
/// [Fiat-Shamir heuristic], a method for converting an interactive
/// challenge/response-based proof-of-knowledge protocol into an offline
/// digital signature through the use of a random oracle, i.e. a digest
/// function.
///
/// The security of such protocols critically rests upon the inability of
/// an attacker to solve for the output of the random oracle, as generally
/// otherwise such signature algorithms are a system of linear equations and
/// therefore doing so would allow the attacker to trivially forge signatures.
///
/// To prevent misuse which would potentially allow this to be possible, this
/// API accepts a [`Digest`] instance, rather than a raw digest value.
///
/// [Fiat-Shamir heuristic]: https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic
#[cfg(feature = "digest-preview")]
#[cfg_attr(docsrs, doc(cfg(feature = "digest-preview")))]
pub trait DigestVerifier<D, S>
where
D: Digest,
Expand Down