aranya_crypto_core/
signer.rs

1//! Digital Signatures.
2
3#![forbid(unsafe_code)]
4
5use core::{
6    borrow::Borrow,
7    fmt::{self, Debug},
8    num::NonZeroU16,
9    result::Result,
10};
11
12use aranya_buggy::Bug;
13
14use crate::{
15    asn1::EncodingError,
16    import::Import,
17    keys::{PublicKey, SecretKey},
18    AlgId,
19};
20
21/// An error from a [`Signer`].
22#[derive(Debug, Eq, PartialEq)]
23pub enum SignerError {
24    /// An unknown or internal error has occurred.
25    Other(&'static str),
26    /// The imported signature is invalid.
27    Encoding(EncodingError),
28    /// The signature could not be verified.
29    Verification,
30    /// [`Signer::verify_batch`] was called with different
31    /// lengths for messages, signatures, or verifying keys.
32    InvalidBatchLengths,
33    /// An internal error was discovered.
34    Bug(Bug),
35}
36
37impl fmt::Display for SignerError {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match self {
40            Self::Other(msg) => write!(f, "{}", msg),
41            Self::Encoding(err) => write!(f, "{}", err),
42            Self::Verification => write!(f, "unable to verify signature"),
43            Self::InvalidBatchLengths => write!(f, "invalid `verify_batch` lengths"),
44            Self::Bug(err) => write!(f, "{err}"),
45        }
46    }
47}
48
49impl core::error::Error for SignerError {
50    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
51        match self {
52            Self::Other(_) => None,
53            Self::Encoding(err) => Some(err),
54            Self::Verification => None,
55            Self::InvalidBatchLengths => None,
56            Self::Bug(err) => Some(err),
57        }
58    }
59}
60
61impl From<EncodingError> for SignerError {
62    fn from(err: EncodingError) -> Self {
63        Self::Encoding(err)
64    }
65}
66
67impl From<Bug> for SignerError {
68    fn from(err: Bug) -> Self {
69        Self::Bug(err)
70    }
71}
72
73/// Digital signature algorithm identifiers.
74#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, AlgId)]
75pub enum SignerId {
76    /// ECDSA using NIST Curve P-256.
77    #[alg_id(0x0001)]
78    P256,
79    /// ECDSA using NIST Curve P-384.
80    #[alg_id(0x0002)]
81    P384,
82    /// ECDSA using NIST Curve P-521.
83    #[alg_id(0x0003)]
84    P521,
85    /// EdDSA using Ed25519.
86    #[alg_id(0x0004)]
87    Ed25519,
88    /// EdDSA using Ed448.
89    #[alg_id(0x0005)]
90    Ed448,
91    /// Some other digital signature algorithm.
92    #[alg_id(Other)]
93    Other(NonZeroU16),
94}
95
96/// Signer is a digital signature algorithm.
97///
98/// # Requirements
99///
100/// The algorithm must:
101///
102/// * Have at minimum a 128-bit security level.
103/// * Generate canonical signatures.
104/// * Reject non-canonical signatures.
105/// * Be EUF-CMA secure.
106///
107/// Note that rejecting non-canonical signatures implies strong
108/// EUF-CMA security. However, this API's definition is
109/// intentionally weaker.
110///
111/// Examples of algorithms that fulfill these requirements
112/// include ECDSA with the three NIST prime-order curves (P-256,
113/// P-384, and P521), albeit with minor modifications (like
114/// rejecting s >= N/2).
115pub trait Signer {
116    /// Uniquely identifies the signature algorithm.
117    const ID: SignerId;
118
119    /// A private key used to create signatures.
120    type SigningKey: SigningKey<Self>;
121    /// A public key used verify signatures.
122    type VerifyingKey: VerifyingKey<Self>;
123    /// A digital signature.
124    type Signature: Signature<Self>;
125
126    /// Verifies all (message, signature, verifying key) tuples
127    /// as a batch.
128    ///
129    /// For some digital signature schemes, batch verification
130    /// can differ from regular signature verification. For
131    /// example, see some [Ed25519 quirks][quirks]. This function
132    /// MUST NOT diverge from regular signature verification.
133    ///
134    /// [quirks]: https://hdevalence.ca/blog/2020-10-04-its-25519am
135    fn verify_batch(
136        msgs: &[&[u8]],
137        sigs: &[Self::Signature],
138        pks: &[Self::VerifyingKey],
139    ) -> Result<(), SignerError> {
140        if msgs.len() != sigs.len() || sigs.len() != pks.len() {
141            return Err(SignerError::InvalidBatchLengths);
142        }
143        for (msg, (sig, pk)) in msgs.iter().zip(sigs.iter().zip(pks)) {
144            pk.verify(msg, sig)?;
145        }
146        Ok(())
147    }
148}
149
150/// An asymmetric secret key used to create digital signatures.
151pub trait SigningKey<T: Signer + ?Sized>: SecretKey {
152    /// Returns the signature over `msg`, which must NOT be
153    /// pre-hashed.
154    fn sign(&self, msg: &[u8]) -> Result<T::Signature, SignerError>;
155
156    /// Returns the public half of the key.
157    fn public(&self) -> Result<T::VerifyingKey, PkError>;
158}
159
160/// Handles Public Key errors
161#[derive(Debug, Eq, PartialEq)]
162pub struct PkError(pub(crate) &'static str);
163
164impl PkError {
165    // Exported for `aranya-crypto`. Do not use.
166    #[doc(hidden)]
167    pub const fn msg(&self) -> &'static str {
168        self.0
169    }
170}
171
172impl fmt::Display for PkError {
173    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174        write!(f, "{}", self.0)
175    }
176}
177
178impl core::error::Error for PkError {}
179
180/// An asymmetric public key used to verify digital signatures.
181pub trait VerifyingKey<T: Signer + ?Sized>: PublicKey {
182    /// Reports whether the signature over `msg` is valid.
183    fn verify(&self, msg: &[u8], sig: &T::Signature) -> Result<(), SignerError>;
184}
185
186/// A canonical digital signature.
187pub trait Signature<T: Signer + ?Sized>: Clone + Debug + for<'a> Import<&'a [u8]> {
188    /// The fixed-length byte encoding of the signature.
189    ///
190    /// This should be `[u8; N]` or similar.
191    type Data: Borrow<[u8]> + Clone + Sized;
192
193    /// Returns the byte encoding of the signature.
194    fn export(&self) -> Self::Data;
195}