From db447a0002484c660e212d9115d94b49833e9a91 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 6 May 2025 10:23:11 -0700 Subject: [PATCH] signature: remove `derive` feature --- .github/workflows/signature.yml | 19 -- Cargo.toml | 1 - signature/CHANGELOG.md | 3 +- signature/Cargo.toml | 1 - signature/src/lib.rs | 6 - signature/src/prehash_signature.rs | 5 - signature/tests/derive.rs | 85 ------- signature_derive/CHANGELOG.md | 76 ------ signature_derive/Cargo.toml | 21 -- signature_derive/LICENSE-APACHE | 201 --------------- signature_derive/LICENSE-MIT | 25 -- signature_derive/README.md | 41 --- signature_derive/src/lib.rs | 392 ----------------------------- 13 files changed, 1 insertion(+), 875 deletions(-) delete mode 100644 signature/tests/derive.rs delete mode 100644 signature_derive/CHANGELOG.md delete mode 100644 signature_derive/Cargo.toml delete mode 100644 signature_derive/LICENSE-APACHE delete mode 100644 signature_derive/LICENSE-MIT delete mode 100644 signature_derive/README.md delete mode 100644 signature_derive/src/lib.rs diff --git a/.github/workflows/signature.yml b/.github/workflows/signature.yml index 00e6f0a20..1105f50b1 100644 --- a/.github/workflows/signature.yml +++ b/.github/workflows/signature.yml @@ -4,7 +4,6 @@ on: pull_request: paths: - "signature/**" - - "signature-derive/**" - "Cargo.*" push: branches: master @@ -37,9 +36,7 @@ jobs: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - run: cargo build --target ${{ matrix.target }} --release --no-default-features - - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rand_core - - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features derive,rand_core minimal-versions: if: false # disabled until we stop using pre-releases @@ -63,19 +60,3 @@ jobs: - run: cargo test --release --no-default-features - run: cargo test --release - run: cargo test --release --all-features - - derive: - runs-on: ubuntu-latest - strategy: - matrix: - rust: - - 1.85.0 # MSRV - - stable - steps: - - uses: actions/checkout@v4 - - uses: RustCrypto/actions/cargo-cache@master - - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.rust }} - - run: cargo test --release - working-directory: signature_derive diff --git a/Cargo.toml b/Cargo.toml index dda804d3c..6d87a02f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ members = [ "elliptic-curve", "kem", "password-hash", - "signature_derive", "universal-hash", "signature", ] diff --git a/signature/CHANGELOG.md b/signature/CHANGELOG.md index d18641cf9..1f0304fbf 100644 --- a/signature/CHANGELOG.md +++ b/signature/CHANGELOG.md @@ -9,15 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `RandomizedSignerMut` trait ([#1448]) ### Changed -- Replace `signature_derive` with blanket impls ([#1827]) - Edition changed to 2024 and MSRV bumped to 1.85 ([#1759]) ### Removed - `std` feature - replaced with `core::error::Error` +- `derive` feature [#1448]: https://github.com/RustCrypto/traits/pull/1448 [#1759]: https://github.com/RustCrypto/traits/pull/1759 -[#1827]: https://github.com/RustCrypto/traits/pull/1827 ## 2.2.0 (2023-11-12) ### Changed diff --git a/signature/Cargo.toml b/signature/Cargo.toml index 168377c1d..6e50f3822 100644 --- a/signature/Cargo.toml +++ b/signature/Cargo.toml @@ -13,7 +13,6 @@ categories = ["cryptography", "no-std"] description = "Traits for cryptographic signature algorithms (e.g. ECDSA, Ed25519)" [dependencies] -derive = { package = "signature_derive", version = "2", optional = true, path = "../signature_derive" } digest = { version = "=0.11.0-pre.10", optional = true, default-features = false } rand_core = { version = "0.9", optional = true, default-features = false } diff --git a/signature/src/lib.rs b/signature/src/lib.rs index 963031ab9..b8678e329 100644 --- a/signature/src/lib.rs +++ b/signature/src/lib.rs @@ -145,12 +145,6 @@ mod prehash_signature; pub use crate::{encoding::*, error::*, keypair::*, signer::*, verifier::*}; -#[cfg(feature = "derive")] -pub use derive::{Signer, Verifier}; - -#[cfg(all(feature = "derive", feature = "digest"))] -pub use derive::{DigestSigner, DigestVerifier}; - #[cfg(feature = "digest")] pub use {crate::prehash_signature::*, digest}; diff --git a/signature/src/prehash_signature.rs b/signature/src/prehash_signature.rs index d9a86456d..773dc6ff9 100644 --- a/signature/src/prehash_signature.rs +++ b/signature/src/prehash_signature.rs @@ -19,11 +19,6 @@ use crate::{ /// This approach is relatively common in signature schemes based on the /// [Fiat-Shamir heuristic]. /// -/// For signature types that implement this trait, when the `derive` crate -/// 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 pub trait PrehashSignature { /// Preferred `Digest` algorithm to use when computing this signature type. diff --git a/signature/tests/derive.rs b/signature/tests/derive.rs deleted file mode 100644 index 989890271..000000000 --- a/signature/tests/derive.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! Tests for code generated by `signature_derive` - -#![cfg(all(feature = "derive", feature = "digest"))] - -use digest::{Digest, OutputSizeUser, array::Array}; -use hex_literal::hex; -use sha2::Sha256; -use signature::{ - DigestSigner, DigestVerifier, Error, PrehashSignature, SignatureEncoding, Signer, Verifier, - hazmat::{PrehashSigner, PrehashVerifier}, -}; - -/// 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"); - -type Repr = Array::OutputSize>; - -/// Dummy signature which just contains a digest output -#[derive(Clone, Debug)] -struct DummySignature(Repr); - -impl PrehashSignature for DummySignature { - type Digest = Sha256; -} - -impl SignatureEncoding for DummySignature { - type Repr = Repr; -} - -impl TryFrom<&[u8]> for DummySignature { - type Error = Error; - - fn try_from(bytes: &[u8]) -> Result { - bytes - .try_into() - .map(DummySignature) - .map_err(|_| Error::new()) - } -} - -impl From for Repr { - fn from(sig: DummySignature) -> Repr { - sig.0 - } -} - -/// Dummy signer which just returns the message digest as a `DummySignature` -#[derive(Signer, DigestSigner, Default)] -struct DummySigner {} - -impl PrehashSigner for DummySigner { - fn sign_prehash(&self, prehash: &[u8]) -> signature::Result { - DummySignature::try_from(prehash) - } -} - -/// 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, DigestVerifier, Default)] -struct DummyVerifier {} - -impl PrehashVerifier for DummyVerifier { - fn verify_prehash(&self, prehash: &[u8], signature: &DummySignature) -> signature::Result<()> { - assert_eq!(signature.to_bytes().as_slice(), prehash); - Ok(()) - } -} - -#[test] -fn derived_signer_impl() { - let sig: DummySignature = DummySigner::default().sign(INPUT_STRING); - assert_eq!(sig.to_bytes().as_slice(), INPUT_STRING_DIGEST) -} - -#[test] -fn derived_verifier_impl() { - let sig: DummySignature = DummySigner::default().sign(INPUT_STRING); - assert!(DummyVerifier::default().verify(INPUT_STRING, &sig).is_ok()); -} diff --git a/signature_derive/CHANGELOG.md b/signature_derive/CHANGELOG.md deleted file mode 100644 index e88b15da1..000000000 --- a/signature_derive/CHANGELOG.md +++ /dev/null @@ -1,76 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## 2.2.0 (UNRELEASED) -### Changed -- Edition changed to 2024 and MSRV bumped to 1.85 ([#1759]) - -[#1759]: https://github.com/RustCrypto/traits/pull/1759 - -## 2.1.0 (2023-11-12) -### Changed -- MSRV 1.60 ([#1387]) - -[#1387]: https://github.com/RustCrypto/traits/pull/1387 - -## 2.0.1 (2023-04-17) -### Changed -- Bump `syn` to v2 ([#1299]) - -[#1299]: https://github.com/RustCrypto/traits/pull/1299 - -## 2.0.0 (2023-01-15) -### Changed -- `Signature` trait has been removed, so don't emit it in custom derive ([#1141]) - -[#1141]: https://github.com/RustCrypto/traits/pull/1141 - -## 1.0.0-pre.7 (2022-09-16) -### Fixed -- Support for `where` bounds ([#1118]) - -[#1118]: https://github.com/RustCrypto/traits/pull/1118 - -## 1.0.0-pre.6 (2022-09-12) -### Added -- `DigestSigner`/`DigestVerifier` support ([#1103]) - -### Removed -- `synstructure` dependency ([#1100]) - -[#1100]: https://github.com/RustCrypto/traits/pull/1100 -[#1103]: https://github.com/RustCrypto/traits/pull/1103 - -## 1.0.0-pre.5 (2022-08-14) -### Changed -- Rust 2021 edition upgrade; MSRV 1.56 ([#1081]) - -[#1081]: https://github.com/RustCrypto/traits/pull/1081 - -## 1.0.0-pre.4 (2022-01-04) -### Changed -- Support for new `digest` v0.10 API ([#850]) - -[#850]: https://github.com/RustCrypto/traits/pull/850 - -## 1.0.0-pre.3 (2021-01-06) -### Fixed -- rustdoc links ([#458]) - -[#458]: https://github.com/RustCrypto/traits/pull/458 - -## 1.0.0-pre.2 (2020-04-19) -### Changed -- Rename `DigestSignature` => `PrehashSignature` ([#96]) - -[#96]: https://github.com/RustCrypto/traits/pull/96 - -## 1.0.0-pre.1 (2020-03-08) -### Added -- Initial changelog for `signature_derive` -- rustdoc ([#79]) - -[#79]: https://github.com/RustCrypto/traits/pull/79 diff --git a/signature_derive/Cargo.toml b/signature_derive/Cargo.toml deleted file mode 100644 index 205bfdff6..000000000 --- a/signature_derive/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "signature_derive" -version = "2.2.0" -authors = ["RustCrypto Developers"] -edition = "2024" -rust-version = "1.85" -documentation = "https://docs.rs/signature" -readme = "README.md" -repository = "https://github.com/RustCrypto/traits" -license = "Apache-2.0 OR MIT" -keywords = ["crypto", "ecdsa", "ed25519", "signature", "signing"] -categories = ["cryptography", "no-std"] -description = "Custom derive support for the 'signature' crate" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1" -quote = "1" -syn = "2" diff --git a/signature_derive/LICENSE-APACHE b/signature_derive/LICENSE-APACHE deleted file mode 100644 index 78173fa2e..000000000 --- a/signature_derive/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/signature_derive/LICENSE-MIT b/signature_derive/LICENSE-MIT deleted file mode 100644 index bb7ff7c2c..000000000 --- a/signature_derive/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2019-2025 RustCrypto Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/signature_derive/README.md b/signature_derive/README.md deleted file mode 100644 index 74cd7871b..000000000 --- a/signature_derive/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# `signature` crate custom derive support - -[![crate][crate-image]][crate-link] -[![Docs][docs-image]][docs-link] -[![Build Status][build-image]][build-link] -![Apache2/MIT licensed][license-image] -![Rust Version][rustc-image] -[![Project Chat][chat-image]][chat-link] - -This crate provides proc macros used by the `signature` crate. - -Not intended to be used directly. See the `signature` crate's documentation -for additional details: - -## 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. - -[//]: # (badges) - -[crate-image]: https://img.shields.io/crates/v/signature_derive -[crate-link]: https://crates.io/crates/signature_derive -[docs-image]: https://docs.rs/signature_derive/badge.svg -[docs-link]: https://docs.rs/signature_derive/ -[build-image]: https://github.com/RustCrypto/traits/actions/workflows/signature_derive.yml/badge.svg?branch=master -[build-link]: https://github.com/RustCrypto/traits/actions/workflows/signature_derive.yml?query=branch:master -[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg -[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg -[chat-link]: https://rustcrypto.zulipchat.com/#narrow/channel/260048-signatures diff --git a/signature_derive/src/lib.rs b/signature_derive/src/lib.rs deleted file mode 100644 index bf6a94c5d..000000000 --- a/signature_derive/src/lib.rs +++ /dev/null @@ -1,392 +0,0 @@ -#![crate_type = "proc-macro"] -#![doc = include_str!("../README.md")] -#![forbid(unsafe_code)] -#![warn( - clippy::unwrap_used, - rust_2018_idioms, - trivial_casts, - unused_import_braces, - missing_debug_implementations, - unused_qualifications -)] - -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::quote; -use syn::{ - DeriveInput, Ident, PredicateType, Token, TraitBound, Type, TypeParam, TypeParamBound, - WhereClause, WherePredicate, parse_macro_input, parse_quote, punctuated::Punctuated, -}; - -/// 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() -} - -fn emit_signer_impl(input: DeriveInput) -> TokenStream2 { - let s_ident = Ident::new("__S", Span::call_site()); - - let mut params = DeriveParams::new(input); - params.add_bound(&s_ident, parse_quote!(::signature::PrehashSignature)); - params.add_bound( - &Ident::new("Self", Span::call_site()), - parse_quote!(::signature::DigestSigner<#s_ident::Digest, #s_ident>), - ); - - let name = params.name; - let impl_generics = params.impl_generics; - let ty_generics = params.ty_generics; - let where_clause = params.where_clause; - - quote! { - impl<#(#impl_generics),*> ::signature::Signer<#s_ident> for #name<#(#ty_generics),*> - #where_clause - { - fn try_sign(&self, msg: &[u8]) -> ::signature::Result<#s_ident> { - self.try_sign_digest(#s_ident::Digest::new_with_prefix(msg)) - } - } - } -} - -/// 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() -} - -fn emit_verifier_impl(input: DeriveInput) -> TokenStream2 { - let s_ident = Ident::new("__S", Span::call_site()); - - let mut params = DeriveParams::new(input); - params.add_bound(&s_ident, parse_quote!(::signature::PrehashSignature)); - params.add_bound( - &Ident::new("Self", Span::call_site()), - parse_quote!(::signature::DigestVerifier<#s_ident::Digest, #s_ident>), - ); - - let name = params.name; - let impl_generics = params.impl_generics; - let ty_generics = params.ty_generics; - let where_clause = params.where_clause; - - quote! { - impl<#(#impl_generics),*> ::signature::Verifier<#s_ident> for #name<#(#ty_generics),*> - #where_clause - { - fn verify(&self, msg: &[u8], signature: &#s_ident) -> ::signature::Result<()> { - self.verify_digest(#s_ident::Digest::new_with_prefix(msg), signature) - } - } - } -} - -/// Derive the [`DigestSigner`] trait for a type which impls [`PrehashSigner`]. -/// -/// [`DigestSigner`]: https://docs.rs/signature/latest/signature/trait.DigestSigner.html -/// [`PrehashSigner`]: https://docs.rs/signature/latest/signature/hazmat/trait.PrehashSigner.html -#[proc_macro_derive(DigestSigner)] -pub fn derive_digest_signer(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - emit_digest_signer_impl(input).into() -} - -fn emit_digest_signer_impl(input: DeriveInput) -> TokenStream2 { - let d_ident = Ident::new("__D", Span::call_site()); - let s_ident = Ident::new("__S", Span::call_site()); - - let mut params = DeriveParams::new(input); - params.add_bound(&d_ident, parse_quote!(::signature::digest::Digest)); - params.add_param(&s_ident); - params.add_bound( - &Ident::new("Self", Span::call_site()), - parse_quote!(::signature::hazmat::PrehashSigner<#s_ident>), - ); - - let name = params.name; - let impl_generics = params.impl_generics; - let ty_generics = params.ty_generics; - let where_clause = params.where_clause; - - quote! { - impl<#(#impl_generics),*> ::signature::DigestSigner<#d_ident, #s_ident> for #name<#(#ty_generics),*> - #where_clause - { - fn try_sign_digest(&self, digest: #d_ident) -> ::signature::Result<#s_ident> { - self.sign_prehash(&digest.finalize()) - } - } - } -} - -/// Derive the [`DigestVerifier`] trait for a type which impls [`PrehashVerifier`]. -/// -/// [`DigestVerifier`]: https://docs.rs/signature/latest/signature/trait.DigestVerifier.html -/// [`PrehashVerifier`]: https://docs.rs/signature/latest/signature/hazmat/trait.PrehashVerifier.html -#[proc_macro_derive(DigestVerifier)] -pub fn derive_digest_verifier(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - emit_digest_verifier_impl(input).into() -} - -fn emit_digest_verifier_impl(input: DeriveInput) -> TokenStream2 { - let d_ident = Ident::new("__D", Span::call_site()); - let s_ident = Ident::new("__S", Span::call_site()); - - let mut params = DeriveParams::new(input); - params.add_bound(&d_ident, parse_quote!(::signature::digest::Digest)); - params.add_param(&s_ident); - params.add_bound( - &Ident::new("Self", Span::call_site()), - parse_quote!(::signature::hazmat::PrehashVerifier<#s_ident>), - ); - - let name = params.name; - let impl_generics = params.impl_generics; - let ty_generics = params.ty_generics; - let where_clause = params.where_clause; - - quote! { - impl<#(#impl_generics),*> ::signature::DigestVerifier<#d_ident, #s_ident> for #name<#(#ty_generics),*> - #where_clause - { - fn verify_digest(&self, digest: #d_ident, signature: &#s_ident) -> ::signature::Result<()> { - self.verify_prehash(&digest.finalize(), signature) - } - } - } -} - -/// Derivation parameters parsed from `DeriveInput`. -struct DeriveParams { - /// Name of the struct the trait impls are being added to. - name: Ident, - - /// Generic parameters of `impl`. - impl_generics: Vec, - - /// Generic parameters of the type. - ty_generics: Vec, - - /// Where clause in-progress. - where_clause: WhereClause, -} - -impl DeriveParams { - /// Parse parameters from `DeriveInput`. - fn new(input: DeriveInput) -> Self { - let impl_generics = input.generics.type_params().cloned().collect(); - - let ty_generics = input - .generics - .type_params() - .map(|bound| bound.ident.clone()) - .collect(); - - let where_clause = input - .generics - .where_clause - .clone() - .unwrap_or_else(|| WhereClause { - where_token: ::default(), - predicates: Punctuated::new(), - }); - - Self { - name: input.ident, - impl_generics, - ty_generics, - where_clause, - } - } - - /// Add a generic parameter with the given bound. - fn add_bound(&mut self, name: &Ident, bound: TraitBound) { - if name != "Self" { - self.add_param(name); - } - - let type_path = parse_quote!(#name); - - let mut bounds = Punctuated::new(); - bounds.push(TypeParamBound::Trait(bound)); - - let predicate_type = PredicateType { - lifetimes: None, - bounded_ty: Type::Path(type_path), - colon_token: ::default(), - bounds, - }; - - self.where_clause - .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)] -mod tests { - use super::*; - use syn::parse_quote; - - #[test] - fn signer() { - let input = parse_quote! { - #[derive(Signer)] - struct MySigner - where - C: EllipticCurve - { - scalar: Scalar - } - }; - - let output = emit_signer_impl(input); - - assert_eq!( - output.to_string(), - quote! { - impl ::signature::Signer<__S> for MySigner - where - C: EllipticCurve, - __S: ::signature::PrehashSignature, - Self: ::signature::DigestSigner<__S::Digest, __S> - { - fn try_sign(&self, msg: &[u8]) -> ::signature::Result<__S> { - self.try_sign_digest(__S::Digest::new_with_prefix(msg)) - } - } - } - .to_string() - ); - } - - #[test] - fn verifier() { - let input = parse_quote! { - #[derive(Verifier)] - struct MyVerifier { - point: UncompressedPoint - } - }; - - let output = emit_verifier_impl(input); - - assert_eq!( - output.to_string(), - quote! { - impl ::signature::Verifier<__S> for MyVerifier - where - __S: ::signature::PrehashSignature, - Self: ::signature::DigestVerifier<__S::Digest, __S> - { - fn verify(&self, msg: &[u8], signature: &__S) -> ::signature::Result<()> { - self.verify_digest(__S::Digest::new_with_prefix(msg), signature) - } - } - } - .to_string() - ); - } - - #[test] - fn digest_signer() { - let input = parse_quote! { - #[derive(DigestSigner)] - struct MySigner { - scalar: Scalar - } - }; - - let output = emit_digest_signer_impl(input); - - assert_eq!( - output.to_string(), - quote! { - impl ::signature::DigestSigner<__D, __S> for MySigner - where - __D: ::signature::digest::Digest, - Self: ::signature::hazmat::PrehashSigner<__S> - { - fn try_sign_digest(&self, digest: __D) -> ::signature::Result<__S> { - self.sign_prehash(&digest.finalize()) - } - } - } - .to_string() - ); - } - - #[test] - fn digest_verifier() { - let input = parse_quote! { - #[derive(DigestVerifier)] - struct MyVerifier { - point: UncompressedPoint - } - }; - - let output = emit_digest_verifier_impl(input); - - assert_eq!( - output.to_string(), - quote! { - impl ::signature::DigestVerifier<__D, __S> for MyVerifier - where - __D: ::signature::digest::Digest, - Self: ::signature::hazmat::PrehashVerifier<__S> - { - fn verify_digest(&self, digest: __D, signature: &__S) -> ::signature::Result<()> { - self.verify_prehash(&digest.finalize(), signature) - } - } - } - .to_string() - ); - } -}