Skip to content

Commit

Permalink
signature_derive: remove synstructure dependency (#1100)
Browse files Browse the repository at this point in the history
It wasn't actually being used for anything structural, but rather for
its higher-level proc macro API and testing facilities.

However, both of those aren't too hard to replace, using `syn` for
testing (via `parse_quote!`)
  • Loading branch information
tarcieri committed Sep 9, 2022
1 parent fae070d commit 9d1b5b3
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 104 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

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

1 change: 0 additions & 1 deletion signature/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@ proc-macro = true
proc-macro2 = "1"
quote = "1"
syn = "1"
synstructure = "0.12.2"
225 changes: 123 additions & 102 deletions signature/derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,142 +1,163 @@
#![crate_type = "proc-macro"]
#![doc = include_str!("../README.md")]
#![deny(warnings, unused_import_braces, unused_qualifications)]
#![forbid(unsafe_code)]
#![warn(
clippy::unwrap_used,
rust_2018_idioms,
trivial_casts,
unused_import_braces,
unused_qualifications
)]

extern crate proc_macro;

use proc_macro2::TokenStream;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use synstructure::{decl_derive, AddBounds};
use syn::{parse_macro_input, DeriveInput};

/// Derive the [`Signer`] trait for a type which impls [`DigestSigner`].
///
/// When implementing the [`DigestSigner`] trait for a signature type which
/// itself impl's the [`PrehashSignature`] trait (which marks signature
/// algorithms which are computed using a [`Digest`]), signature providers
/// can automatically derive the [`Signer`] trait when the digest algorithm
/// is [`PrehashSignature::Digest`] (i.e. the "standard" digest algorithm
/// for a given signature type)
///
/// This automates all of the digest computation otherwise needed for a
/// complete signature algorithm implementation.
///
/// [`Digest`]: https://docs.rs/digest/latest/digest/trait.Digest.html
/// [`DigestSigner`]: https://docs.rs/signature/latest/signature/trait.DigestSigner.html
/// [`PrehashSignature`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html
/// [`PrehashSignature::Digest`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html#associated-types
#[proc_macro_derive(Signer)]
pub fn derive_signer(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
emit_signer_impl(input).into()
}

/// Derive the `Signer` trait for `DigestSigner` types
fn derive_signer(mut s: synstructure::Structure) -> TokenStream {
s.add_bounds(AddBounds::None);
s.gen_impl(quote! {
gen impl<S> signature::Signer<S> for @Self
fn emit_signer_impl(input: DeriveInput) -> TokenStream2 {
let ident = input.ident;
let type_params = input.generics.type_params().collect::<Vec<_>>();
let type_idents = type_params
.iter()
.map(|bound| bound.ident.clone())
.collect::<Vec<_>>();

quote! {
impl<S, #(#type_params),*> ::signature::Signer<S> for #ident<#(#type_idents),*>
where
S: signature::PrehashSignature,
Self: signature::DigestSigner<S::Digest, S>
S: ::signature::PrehashSignature,
Self: ::signature::DigestSigner<S::Digest, S>
{
fn try_sign(&self, msg: &[u8]) -> Result<S, signature::Error> {
fn try_sign(&self, msg: &[u8]) -> Result<S, ::signature::Error> {
self.try_sign_digest(S::Digest::new_with_prefix(msg))
}
}
})
}
}

decl_derive! {
[Signer] =>
/// Derive the [`Signer`] trait for a type which impls [`DigestSigner`].
///
/// When implementing the [`DigestSigner`] trait for a signature type which
/// itself impl's the [`PrehashSignature`] trait (which marks signature
/// algorithms which are computed using a [`Digest`]), signature providers
/// can automatically derive the [`Signer`] trait when the digest algorithm
/// is [`PrehashSignature::Digest`] (i.e. the "standard" digest algorithm
/// for a given signature type)
///
/// This automates all of the digest computation otherwise needed for a
/// complete signature algorithm implementation.
///
/// [`Digest`]: https://docs.rs/digest/latest/digest/trait.Digest.html
/// [`DigestSigner`]: https://docs.rs/signature/latest/signature/trait.DigestSigner.html
/// [`PrehashSignature`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html
/// [`PrehashSignature::Digest`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html#associated-types
derive_signer
/// Derive the [`Verifier`] trait for a type which impls [`DigestVerifier`].
///
/// When implementing the [`DigestVerifier`] trait for a signature type which
/// itself impl's the [`PrehashSignature`] trait (which marks signature
/// algorithms which are computed using a [`Digest`]), signature providers
/// can automatically derive the [`Verifier`] trait when the digest algorithm
/// is [`PrehashSignature::Digest`] (i.e. the "standard" digest algorithm
/// for a given signature type)
///
/// This automates all of the digest computation otherwise needed for a
/// complete signature algorithm implementation.
///
/// [`Digest`]: https://docs.rs/digest/latest/digest/trait.Digest.html
/// [`DigestVerifier`]: https://docs.rs/signature/latest/signature/trait.DigestVerifier.html
/// [`PrehashSignature`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html
/// [`PrehashSignature::Digest`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html#associated-types
#[proc_macro_derive(Verifier)]
pub fn derive_verifier(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
emit_verifier_impl(input).into()
}

/// Derive the `Verifier` trait for `DigestVerifier` types
fn derive_verifier(mut s: synstructure::Structure) -> TokenStream {
s.add_bounds(AddBounds::None);
s.gen_impl(quote! {
gen impl<S> signature::Verifier<S> for @Self
fn emit_verifier_impl(input: DeriveInput) -> TokenStream2 {
let ident = input.ident;
let type_params = input.generics.type_params().collect::<Vec<_>>();
let type_idents = type_params
.iter()
.map(|bound| bound.ident.clone())
.collect::<Vec<_>>();

quote! {
impl<S, #(#type_params),*> ::signature::Verifier<S> for #ident<#(#type_idents),*>
where
S: signature::PrehashSignature,
Self: signature::DigestVerifier<S::Digest, S>
S: ::signature::PrehashSignature,
Self: ::signature::DigestVerifier<S::Digest, S>
{
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), signature::Error> {
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), ::signature::Error> {
self.verify_digest(S::Digest::new_with_prefix(msg), signature)
}
}
})
}

decl_derive! {
[Verifier] =>
/// Derive the [`Verifier`] trait for a type which impls [`DigestVerifier`].
///
/// When implementing the [`DigestVerifier`] trait for a signature type which
/// itself impl's the [`PrehashSignature`] trait (which marks signature
/// algorithms which are computed using a [`Digest`]), signature providers
/// can automatically derive the [`Verifier`] trait when the digest algorithm
/// is [`PrehashSignature::Digest`] (i.e. the "standard" digest algorithm
/// for a given signature type)
///
/// This automates all of the digest computation otherwise needed for a
/// complete signature algorithm implementation.
///
/// [`Digest`]: https://docs.rs/digest/latest/digest/trait.Digest.html
/// [`DigestVerifier`]: https://docs.rs/signature/latest/signature/trait.DigestVerifier.html
/// [`PrehashSignature`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html
/// [`PrehashSignature::Digest`]: https://docs.rs/signature/latest/signature/trait.PrehashSignature.html#associated-types
derive_verifier
}
}

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

#[test]
fn signer() {
test_derive! {
derive_signer {
struct MySigner<C: EllipticCurve> {
scalar: Scalar<C::ScalarSize>
}
let input = parse_quote! {
#[derive(Signer)]
struct MySigner<C: EllipticCurve> {
scalar: Scalar<C::ScalarSize>
}
expands to {
#[allow(non_upper_case_globals)]
const _DERIVE_signature_Signer_S_FOR_MySigner: () = {
impl<S, C: EllipticCurve> signature::Signer<S> for MySigner<C>
where
S: signature::PrehashSignature,
Self: signature::DigestSigner<S::Digest, S>
{
fn try_sign(&self, msg: &[u8]) -> Result <S, signature::Error> {
self.try_sign_digest(S::Digest::new_with_prefix(msg))
}
};

let output = emit_signer_impl(input);

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

#[test]
fn verifier() {
test_derive! {
derive_verifier {
struct MyVerifier<C: EllipticCurve> {
point: UncompressedPoint<C>
}
let input = parse_quote! {
#[derive(Verifier)]
struct MyVerifier<C: EllipticCurve> {
point: UncompressedPoint<C>
}
expands to {
#[allow(non_upper_case_globals)]
const _DERIVE_signature_Verifier_S_FOR_MyVerifier: () = {
impl<S, C: EllipticCurve> signature::Verifier<S> for MyVerifier<C>
where
S: signature::PrehashSignature,
Self: signature::DigestVerifier<S::Digest, S>
{
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), signature::Error> {
self.verify_digest(S::Digest::new_with_prefix(msg), signature)
}
};

let output = emit_verifier_impl(input);

assert_eq!(
output.to_string(),
quote! {
impl<S, C: EllipticCurve> ::signature::Verifier<S> for MyVerifier<C>
where
S: ::signature::PrehashSignature,
Self: ::signature::DigestVerifier<S::Digest, S>
{
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), ::signature::Error> {
self.verify_digest(S::Digest::new_with_prefix(msg), signature)
}
};
}
}
no_build // tests in `signature-crate/tests`
}
.to_string()
);
}
}

0 comments on commit 9d1b5b3

Please sign in to comment.