Skip to content
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ install:

script:
- cargo test --verbose --release
- cargo test --verbose --all-features --release
# Can't use `--no-default-features` with a workspace. See rust-lang/cargo#4753
- cd signature-crate && cargo build --no-default-features --release

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ members = [
"ecdsa",
"ed25519",
"signature-crate",
"signature-crate/signature_derive"
]
5 changes: 5 additions & 0 deletions signature-crate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ categories = ["cryptography", "no-std"]

[dependencies]
digest = { version = "0.8", optional = true, default-features = false }
signature_derive = { version = "0", optional = true, path = "signature_derive" }

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

[features]
default = ["digest", "std"]
Expand Down
31 changes: 28 additions & 3 deletions signature-crate/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# `signature` crate

[![Build Status](https://travis-ci.org/RustCrypto/signatures.svg?branch=master)](https://travis-ci.org/RustCrypto/signatures)
[![crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
![Apache2/MIT licensed][license-image]
![Rust Version][rustc-image]
[![Build Status][build-image]][build-link]

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

The long-term goal is to use this crate in conjunction with the
[`ecdsa`][ecdsa-crate] and [`ed25519`][ed25519-crate], however those crates
are a work-in-progress.

[Documentation][docs-link]

## License

Expand All @@ -20,4 +30,19 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

[1]: https://en.wikipedia.org/wiki/Digital_signature
[//]: # (badges)

[crate-image]: https://img.shields.io/crates/v/signature.svg
[crate-link]: https://crates.io/crates/signature
[docs-image]: https://docs.rs/signature/badge.svg
[docs-link]: https://docs.rs/signature/
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.31+-blue.svg
[build-image]: https://travis-ci.org/RustCrypto/signatures.svg?branch=master
[build-link]: https://travis-ci.org/RustCrypto/signatures

[//]: # (general links)

[digital signatures]: https://en.wikipedia.org/wiki/Digital_signature
[ecdsa-crate]: https://github.com/RustCrypto/signatures/tree/master/ecdsa
[ed25519-crate]: https://github.com/RustCrypto/signatures/tree/master/ed25519
21 changes: 21 additions & 0 deletions signature-crate/signature_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "signature_derive"
version = "0.0.0"
authors = ["RustCrypto Developers"]
license = "Apache-2.0 OR MIT"
description = "Custom derive support for the 'signature' crate"
documentation = "https://docs.rs/signature"
repository = "https://github.com/RustCrypto/signatures/tree/master/signature-crate/"
readme = "README.md"
edition = "2018"
keywords = ["crypto", "ecdsa", "ed25519", "signature", "signing"]
categories = ["cryptography", "no-std"]

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "0.4"
quote = "0.6"
syn = "0.15"
synstructure = "0.10"
27 changes: 27 additions & 0 deletions signature-crate/signature_derive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# `signature` crate custom derive support

[![Build Status](https://travis-ci.org/RustCrypto/signatures.svg?branch=master)](https://travis-ci.org/RustCrypto/signatures)

This crate provides proc macros used by the `signature` crate.

It's not intended to be used directly. See the signature crate's documentation
for additional details:

[Documentation][docs]

## License

All crates licensed under either of

* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* [MIT license](http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

[Documentation]: https://docs.rs/signature/
115 changes: 115 additions & 0 deletions signature-crate/signature_derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//! Custom derive support for the `signature` crate.
//!
//! This crate can be used to derive `Signer` and `Verifier` impls for
//! types that impl `DigestSigner` or `DigestVerifier` respectively.

#![crate_type = "proc-macro"]
#![recursion_limit = "128"]
#![deny(warnings, unused_import_braces, unused_qualifications)]
#![forbid(unsafe_code)]

extern crate proc_macro;

use proc_macro2::TokenStream;
use quote::quote;
use synstructure::{decl_derive, AddBounds};

/// Derive the `Signer` trait for `DigestSigner` types
fn derive_signer(mut s: synstructure::Structure) -> TokenStream {
s.add_bounds(AddBounds::None);
s.gen_impl(quote! {
use signature::{DigestSignature, DigestSigner, Error};

gen impl<S> Signer<S> for @Self
where
S: DigestSignature,
Self: DigestSigner<S::Digest, S>,
{
fn try_sign(&self, msg: &[u8]) -> Result<S, Error> {
self.try_sign_digest(S::Digest::new().chain(msg))
}
}
})
}
decl_derive!([Signer] => derive_signer);

/// Derive the `Verifier` trait for `DigestVerifier` types
fn derive_verifier(mut s: synstructure::Structure) -> TokenStream {
s.add_bounds(AddBounds::None);
s.gen_impl(quote! {
use signature::{DigestSignature, DigestVerifier, Error};

gen impl<S> Verifier<S> for @Self
where
S: DigestSignature,
Self: DigestVerifier<S::Digest, S>,
{
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), Error> {
self.verify_digest(S::Digest::new().chain(msg), signature)
}
}
})
}
decl_derive!([Verifier] => derive_verifier);

#[cfg(test)]
mod tests {
use super::*;
use synstructure::test_derive;

#[test]
fn signer() {
test_derive! {
derive_signer {
struct MySigner<C: EllipticCurve> {
scalar: Scalar<C::ScalarSize>
}
}
expands to {
#[allow(non_upper_case_globals)]
const _DERIVE_Signer_S_FOR_MySigner: () = {
use signature::{DigestSignature, DigestSigner, Error};

impl<S, C: EllipticCurve> Signer<S> for MySigner<C>
where
S: DigestSignature,
Self: DigestSigner<S::Digest, S>,
{
fn try_sign(&self, msg: &[u8]) -> Result <S, Error> {
self.try_sign_digest(S::Digest::new().chain(msg))
}
}
};
}
no_build // tests in `signature-crate/tests`
}
}

#[test]
fn verifier() {
test_derive! {
derive_verifier {
struct MyVerifier<C: EllipticCurve> {
point: UncompressedPoint<C>
}
}
expands to {
#[allow(non_upper_case_globals)]
const _DERIVE_Verifier_S_FOR_MyVerifier: () = {
use signature::{DigestSignature, DigestVerifier, Error};

impl<S, C: EllipticCurve> Verifier<S> for MyVerifier<C>
where
S: DigestSignature,
Self: DigestVerifier<S::Digest, S>,
{
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), Error> {
self.verify_digest(S::Digest::new().chain(msg), signature)
}
}
};
}
no_build // tests in `signature-crate/tests`
}
}
}
11 changes: 10 additions & 1 deletion signature-crate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,17 @@
#[macro_use]
extern crate std;

#[cfg(feature = "signature_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate signature_derive;

#[cfg(feature = "signature_derive")]
#[doc(hidden)]
pub use signature_derive::{Signer, Verifier};

#[cfg(feature = "digest")]
pub extern crate digest;
pub use digest;

mod error;
mod prelude;
Expand Down
16 changes: 16 additions & 0 deletions signature-crate/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,19 @@ pub trait Signature: AsRef<[u8]> + Debug + Sized {
self.as_slice().into()
}
}

/// Marker trait for `Signature` types computable as `S(H(m))`
///
/// - `S`: signature algorithm
/// - `H`: hash (a.k.a. digest) function
/// - `m`: message
///
/// For signature types that implement this trait, a blanket impl of
/// `Signer` will be provided for all types that `impl DigestSigner`
/// along with a corresponding impl of `Verifier` for all types that
/// `impl DigestVerifier`.
#[cfg(feature = "digest")]
pub trait DigestSignature: Signature {
/// Preferred `Digest` algorithm to use when computing this signature type.
type Digest: digest::Digest;
}
13 changes: 0 additions & 13 deletions signature-crate/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,6 @@ where
D: Digest,
S: Signature,
{
/// Sign the computed digest of the given message.
///
/// Panics in the event of a signing error.
fn sign_msg_digest(&self, msg: &[u8]) -> S {
self.try_sign_msg_digest(msg)
.expect("signature operation failed")
}

/// Attempt to sign the computed digest of the given message.
fn try_sign_msg_digest(&self, msg: &[u8]) -> Result<S, Error> {
self.try_sign_digest(D::new().chain(msg))
}

/// Sign the given prehashed message `Digest`, returning a signature.
///
/// Panics in the event of a signing error.
Expand Down
5 changes: 0 additions & 5 deletions signature-crate/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ where
D: Digest,
S: Signature,
{
/// Verify the signature against the computed `Digest` output.
fn verify_msg_digest(&self, msg: &[u8], signature: &S) -> Result<(), Error> {
self.verify_digest(D::new().chain(msg), signature)
}

/// Verify the signature against the given `Digest` output.
fn verify_digest(&self, digest: D, signature: &S) -> Result<(), Error>;
}
76 changes: 76 additions & 0 deletions signature-crate/tests/signature_derive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/// "Tests" for code generated by `signature_derive`
#[cfg(all(test, feature = "signature_derive"))]
mod tests {
use digest::{generic_array::GenericArray, Digest};
use hex_literal::hex;
use sha2::Sha256;
use signature::{
DigestSignature, DigestSigner, DigestVerifier, Error, Signature, Signer, Verifier,
};

/// Test vector to compute SHA-256 digest of
const INPUT_STRING: &[u8] = b"abc";

/// Expected SHA-256 digest for the input string
const INPUT_STRING_DIGEST: [u8; 32] =
hex!("ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad");

/// Dummy signature which just contains a digest output
#[derive(Debug)]
struct DummySignature(GenericArray<u8, <Sha256 as Digest>::OutputSize>);

impl Signature for DummySignature {
fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, Error> {
Ok(DummySignature(GenericArray::clone_from_slice(
bytes.as_ref(),
)))
}
}

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

impl DigestSignature for DummySignature {
type Digest = Sha256;
}

/// Dummy signer which just returns the message digest as a `DummySignature`
#[derive(Signer, Default)]
struct DummySigner {}

impl DigestSigner<Sha256, DummySignature> for DummySigner {
fn try_sign_digest(&self, digest: Sha256) -> Result<DummySignature, Error> {
DummySignature::from_bytes(digest.result())
}
}

/// Dummy verifier which ensures the `DummySignature` digest matches the
/// expected value.
///
/// Panics (via `assert_eq!`) if the value is not what is expected.
#[derive(Verifier, Default)]
struct DummyVerifier {}

impl DigestVerifier<Sha256, DummySignature> for DummyVerifier {
fn verify_digest(&self, digest: Sha256, signature: &DummySignature) -> Result<(), Error> {
let actual_digest = digest.result();
assert_eq!(signature.as_ref(), actual_digest.as_ref());
Ok(())
}
}

#[test]
fn derived_signer_impl() {
let sig: DummySignature = DummySigner::default().sign(INPUT_STRING);
assert_eq!(sig.as_ref(), INPUT_STRING_DIGEST.as_ref())
}

#[test]
fn derived_verifier_impl() {
let sig: DummySignature = DummySigner::default().sign(INPUT_STRING);
assert!(DummyVerifier::default().verify(INPUT_STRING, &sig).is_ok());
}
}