Coverage Report

Created: 2026-02-14 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ecdsa-0.16.9/src/verifying.rs
Line
Count
Source
1
//! ECDSA verifying: checking signatures are authentic using a [`VerifyingKey`].
2
3
use crate::{
4
    hazmat::{bits2field, DigestPrimitive, VerifyPrimitive},
5
    Error, Result, Signature, SignatureSize,
6
};
7
use core::{cmp::Ordering, fmt::Debug};
8
use elliptic_curve::{
9
    generic_array::ArrayLength,
10
    point::PointCompression,
11
    sec1::{self, CompressedPoint, EncodedPoint, FromEncodedPoint, ToEncodedPoint},
12
    AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey,
13
};
14
use signature::{
15
    digest::{Digest, FixedOutput},
16
    hazmat::PrehashVerifier,
17
    DigestVerifier, Verifier,
18
};
19
20
#[cfg(feature = "alloc")]
21
use alloc::boxed::Box;
22
23
#[cfg(feature = "der")]
24
use {crate::der, core::ops::Add};
25
26
#[cfg(feature = "pem")]
27
use {
28
    core::str::FromStr,
29
    elliptic_curve::pkcs8::{DecodePublicKey, EncodePublicKey},
30
};
31
32
#[cfg(feature = "pkcs8")]
33
use elliptic_curve::pkcs8::{
34
    self,
35
    der::AnyRef,
36
    spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
37
    AssociatedOid, ObjectIdentifier,
38
};
39
40
#[cfg(feature = "sha2")]
41
use {
42
    crate::{
43
        SignatureWithOid, ECDSA_SHA224_OID, ECDSA_SHA256_OID, ECDSA_SHA384_OID, ECDSA_SHA512_OID,
44
    },
45
    sha2::{Sha224, Sha256, Sha384, Sha512},
46
};
47
48
#[cfg(all(feature = "pem", feature = "serde"))]
49
use serdect::serde::{de, ser, Deserialize, Serialize};
50
51
/// ECDSA public key used for verifying signatures. Generic over prime order
52
/// elliptic curves (e.g. NIST P-curves)
53
///
54
/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve, and a
55
/// [`VerifyPrimitive`] impl on its associated `AffinePoint` type.
56
///
57
/// ## Usage
58
///
59
/// The [`signature`] crate defines the following traits which are the
60
/// primary API for verifying:
61
///
62
/// - [`Verifier`]: verify a message against a provided key and signature
63
/// - [`DigestVerifier`]: verify a message [`Digest`] against a provided key and signature
64
/// - [`PrehashVerifier`]: verify the low-level raw output bytes of a message digest
65
///
66
/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html)
67
/// for examples of using this type with a concrete elliptic curve.
68
///
69
/// # `serde` support
70
///
71
/// When the `serde` feature of this crate is enabled, it provides support for
72
/// serializing and deserializing ECDSA signatures using the `Serialize` and
73
/// `Deserialize` traits.
74
///
75
/// The serialization leverages the encoding used by the [`PublicKey`] type,
76
/// which is a binary-oriented ASN.1 DER encoding.
77
#[derive(Clone, Debug)]
78
pub struct VerifyingKey<C>
79
where
80
    C: PrimeCurve + CurveArithmetic,
81
{
82
    pub(crate) inner: PublicKey<C>,
83
}
84
85
impl<C> VerifyingKey<C>
86
where
87
    C: PrimeCurve + CurveArithmetic,
88
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
89
    FieldBytesSize<C>: sec1::ModulusSize,
90
{
91
    /// Initialize [`VerifyingKey`] from a SEC1-encoded public key.
92
0
    pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
93
0
        PublicKey::from_sec1_bytes(bytes)
94
0
            .map(|pk| Self { inner: pk })
95
0
            .map_err(|_| Error::new())
96
0
    }
97
98
    /// Initialize [`VerifyingKey`] from an affine point.
99
    ///
100
    /// Returns an [`Error`] if the given affine point is the additive identity
101
    /// (a.k.a. point at infinity).
102
0
    pub fn from_affine(affine: AffinePoint<C>) -> Result<Self> {
103
        Ok(Self {
104
0
            inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?,
105
        })
106
0
    }
107
108
    /// Initialize [`VerifyingKey`] from an [`EncodedPoint`].
109
0
    pub fn from_encoded_point(public_key: &EncodedPoint<C>) -> Result<Self> {
110
0
        Option::from(PublicKey::<C>::from_encoded_point(public_key))
111
0
            .map(|public_key| Self { inner: public_key })
112
0
            .ok_or_else(Error::new)
113
0
    }
114
115
    /// Serialize this [`VerifyingKey`] as a SEC1 [`EncodedPoint`], optionally
116
    /// applying point compression.
117
3.16k
    pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
118
3.16k
        self.inner.to_encoded_point(compress)
119
3.16k
    }
<ecdsa::verifying::VerifyingKey<p256::NistP256>>::to_encoded_point
Line
Count
Source
117
3.16k
    pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
118
3.16k
        self.inner.to_encoded_point(compress)
119
3.16k
    }
Unexecuted instantiation: <ecdsa::verifying::VerifyingKey<_>>::to_encoded_point
120
121
    /// Convert this [`VerifyingKey`] into the
122
    /// `Elliptic-Curve-Point-to-Octet-String` encoding described in
123
    /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3
124
    /// (page 10).
125
    ///
126
    /// <http://www.secg.org/sec1-v2.pdf>
127
    #[cfg(feature = "alloc")]
128
0
    pub fn to_sec1_bytes(&self) -> Box<[u8]>
129
0
    where
130
0
        C: PointCompression,
131
    {
132
0
        self.inner.to_sec1_bytes()
133
0
    }
134
135
    /// Borrow the inner [`AffinePoint`] for this public key.
136
0
    pub fn as_affine(&self) -> &AffinePoint<C> {
137
0
        self.inner.as_affine()
138
0
    }
139
}
140
141
//
142
// `*Verifier` trait impls
143
//
144
145
impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C>
146
where
147
    C: PrimeCurve + CurveArithmetic,
148
    D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
149
    AffinePoint<C>: VerifyPrimitive<C>,
150
    SignatureSize<C>: ArrayLength<u8>,
151
{
152
0
    fn verify_digest(&self, msg_digest: D, signature: &Signature<C>) -> Result<()> {
153
0
        self.inner.as_affine().verify_digest(msg_digest, signature)
154
0
    }
155
}
156
157
impl<C> PrehashVerifier<Signature<C>> for VerifyingKey<C>
158
where
159
    C: PrimeCurve + CurveArithmetic,
160
    AffinePoint<C>: VerifyPrimitive<C>,
161
    SignatureSize<C>: ArrayLength<u8>,
162
{
163
0
    fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> {
164
0
        let field = bits2field::<C>(prehash)?;
165
0
        self.inner.as_affine().verify_prehashed(&field, signature)
166
0
    }
167
}
168
169
impl<C> Verifier<Signature<C>> for VerifyingKey<C>
170
where
171
    C: PrimeCurve + CurveArithmetic + DigestPrimitive,
172
    AffinePoint<C>: VerifyPrimitive<C>,
173
    SignatureSize<C>: ArrayLength<u8>,
174
{
175
0
    fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> {
176
0
        self.verify_digest(C::Digest::new_with_prefix(msg), signature)
177
0
    }
178
}
179
180
#[cfg(feature = "sha2")]
181
impl<C> Verifier<SignatureWithOid<C>> for VerifyingKey<C>
182
where
183
    C: PrimeCurve + CurveArithmetic + DigestPrimitive,
184
    AffinePoint<C>: VerifyPrimitive<C>,
185
    SignatureSize<C>: ArrayLength<u8>,
186
{
187
    fn verify(&self, msg: &[u8], sig: &SignatureWithOid<C>) -> Result<()> {
188
        match sig.oid() {
189
            ECDSA_SHA224_OID => self.verify_prehash(&Sha224::digest(msg), sig.signature()),
190
            ECDSA_SHA256_OID => self.verify_prehash(&Sha256::digest(msg), sig.signature()),
191
            ECDSA_SHA384_OID => self.verify_prehash(&Sha384::digest(msg), sig.signature()),
192
            ECDSA_SHA512_OID => self.verify_prehash(&Sha512::digest(msg), sig.signature()),
193
            _ => Err(Error::new()),
194
        }
195
    }
196
}
197
198
#[cfg(feature = "der")]
199
impl<C, D> DigestVerifier<D, der::Signature<C>> for VerifyingKey<C>
200
where
201
    C: PrimeCurve + CurveArithmetic,
202
    D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
203
    AffinePoint<C>: VerifyPrimitive<C>,
204
    SignatureSize<C>: ArrayLength<u8>,
205
    der::MaxSize<C>: ArrayLength<u8>,
206
    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
207
{
208
0
    fn verify_digest(&self, msg_digest: D, signature: &der::Signature<C>) -> Result<()> {
209
0
        let signature = Signature::<C>::try_from(signature.clone())?;
210
0
        DigestVerifier::<D, Signature<C>>::verify_digest(self, msg_digest, &signature)
211
0
    }
212
}
213
214
#[cfg(feature = "der")]
215
impl<C> PrehashVerifier<der::Signature<C>> for VerifyingKey<C>
216
where
217
    C: PrimeCurve + CurveArithmetic + DigestPrimitive,
218
    AffinePoint<C>: VerifyPrimitive<C>,
219
    SignatureSize<C>: ArrayLength<u8>,
220
    der::MaxSize<C>: ArrayLength<u8>,
221
    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
222
{
223
0
    fn verify_prehash(&self, prehash: &[u8], signature: &der::Signature<C>) -> Result<()> {
224
0
        let signature = Signature::<C>::try_from(signature.clone())?;
225
0
        PrehashVerifier::<Signature<C>>::verify_prehash(self, prehash, &signature)
226
0
    }
227
}
228
229
#[cfg(feature = "der")]
230
impl<C> Verifier<der::Signature<C>> for VerifyingKey<C>
231
where
232
    C: PrimeCurve + CurveArithmetic + DigestPrimitive,
233
    AffinePoint<C>: VerifyPrimitive<C>,
234
    SignatureSize<C>: ArrayLength<u8>,
235
    der::MaxSize<C>: ArrayLength<u8>,
236
    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
237
{
238
0
    fn verify(&self, msg: &[u8], signature: &der::Signature<C>) -> Result<()> {
239
0
        let signature = Signature::<C>::try_from(signature.clone())?;
240
0
        Verifier::<Signature<C>>::verify(self, msg, &signature)
241
0
    }
242
}
243
244
//
245
// Other trait impls
246
//
247
248
impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C>
249
where
250
    C: PrimeCurve + CurveArithmetic,
251
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
252
    FieldBytesSize<C>: sec1::ModulusSize,
253
{
254
0
    fn as_ref(&self) -> &AffinePoint<C> {
255
0
        self.as_affine()
256
0
    }
257
}
258
259
impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {}
260
261
impl<C> From<VerifyingKey<C>> for CompressedPoint<C>
262
where
263
    C: PrimeCurve + CurveArithmetic + PointCompression,
264
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
265
    FieldBytesSize<C>: sec1::ModulusSize,
266
{
267
0
    fn from(verifying_key: VerifyingKey<C>) -> CompressedPoint<C> {
268
0
        verifying_key.inner.into()
269
0
    }
270
}
271
272
impl<C> From<&VerifyingKey<C>> for CompressedPoint<C>
273
where
274
    C: PrimeCurve + CurveArithmetic + PointCompression,
275
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
276
    FieldBytesSize<C>: sec1::ModulusSize,
277
{
278
0
    fn from(verifying_key: &VerifyingKey<C>) -> CompressedPoint<C> {
279
0
        verifying_key.inner.into()
280
0
    }
281
}
282
283
impl<C> From<VerifyingKey<C>> for EncodedPoint<C>
284
where
285
    C: PrimeCurve + CurveArithmetic + PointCompression,
286
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
287
    FieldBytesSize<C>: sec1::ModulusSize,
288
{
289
0
    fn from(verifying_key: VerifyingKey<C>) -> EncodedPoint<C> {
290
0
        verifying_key.inner.into()
291
0
    }
292
}
293
294
impl<C> From<&VerifyingKey<C>> for EncodedPoint<C>
295
where
296
    C: PrimeCurve + CurveArithmetic + PointCompression,
297
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
298
    FieldBytesSize<C>: sec1::ModulusSize,
299
{
300
0
    fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> {
301
0
        verifying_key.inner.into()
302
0
    }
303
}
304
305
impl<C> Eq for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {}
306
307
impl<C> PartialEq for VerifyingKey<C>
308
where
309
    C: PrimeCurve + CurveArithmetic,
310
{
311
0
    fn eq(&self, other: &Self) -> bool {
312
0
        self.inner.eq(&other.inner)
313
0
    }
314
}
315
316
impl<C> From<PublicKey<C>> for VerifyingKey<C>
317
where
318
    C: PrimeCurve + CurveArithmetic,
319
{
320
3.48k
    fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
321
3.48k
        VerifyingKey { inner: public_key }
322
3.48k
    }
<ecdsa::verifying::VerifyingKey<p256::NistP256> as core::convert::From<elliptic_curve::public_key::PublicKey<p256::NistP256>>>::from
Line
Count
Source
320
3.48k
    fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
321
3.48k
        VerifyingKey { inner: public_key }
322
3.48k
    }
Unexecuted instantiation: <ecdsa::verifying::VerifyingKey<_> as core::convert::From<elliptic_curve::public_key::PublicKey<_>>>::from
323
}
324
325
impl<C> From<&PublicKey<C>> for VerifyingKey<C>
326
where
327
    C: PrimeCurve + CurveArithmetic,
328
{
329
0
    fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> {
330
0
        (*public_key).into()
331
0
    }
332
}
333
334
impl<C> From<VerifyingKey<C>> for PublicKey<C>
335
where
336
    C: PrimeCurve + CurveArithmetic,
337
{
338
0
    fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> {
339
0
        verifying_key.inner
340
0
    }
341
}
342
343
impl<C> From<&VerifyingKey<C>> for PublicKey<C>
344
where
345
    C: PrimeCurve + CurveArithmetic,
346
{
347
0
    fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> {
348
0
        (*verifying_key).into()
349
0
    }
350
}
351
352
impl<C> PartialOrd for VerifyingKey<C>
353
where
354
    C: PrimeCurve + CurveArithmetic,
355
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
356
    FieldBytesSize<C>: sec1::ModulusSize,
357
{
358
0
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
359
0
        self.inner.partial_cmp(&other.inner)
360
0
    }
361
}
362
363
impl<C> Ord for VerifyingKey<C>
364
where
365
    C: PrimeCurve + CurveArithmetic,
366
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
367
    FieldBytesSize<C>: sec1::ModulusSize,
368
{
369
0
    fn cmp(&self, other: &Self) -> Ordering {
370
0
        self.inner.cmp(&other.inner)
371
0
    }
372
}
373
374
impl<C> TryFrom<&[u8]> for VerifyingKey<C>
375
where
376
    C: PrimeCurve + CurveArithmetic,
377
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
378
    FieldBytesSize<C>: sec1::ModulusSize,
379
{
380
    type Error = Error;
381
382
0
    fn try_from(bytes: &[u8]) -> Result<Self> {
383
0
        Self::from_sec1_bytes(bytes)
384
0
    }
385
}
386
387
#[cfg(feature = "pkcs8")]
388
impl<C> AssociatedAlgorithmIdentifier for VerifyingKey<C>
389
where
390
    C: AssociatedOid + CurveArithmetic + PrimeCurve,
391
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
392
    FieldBytesSize<C>: sec1::ModulusSize,
393
{
394
    type Params = ObjectIdentifier;
395
396
    const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> =
397
        PublicKey::<C>::ALGORITHM_IDENTIFIER;
398
}
399
400
#[cfg(feature = "pkcs8")]
401
impl<C> SignatureAlgorithmIdentifier for VerifyingKey<C>
402
where
403
    C: PrimeCurve + CurveArithmetic,
404
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
405
    FieldBytesSize<C>: sec1::ModulusSize,
406
    Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
407
{
408
    type Params = AnyRef<'static>;
409
410
    const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
411
        Signature::<C>::ALGORITHM_IDENTIFIER;
412
}
413
414
#[cfg(feature = "pkcs8")]
415
impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<C>
416
where
417
    C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
418
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
419
    FieldBytesSize<C>: sec1::ModulusSize,
420
{
421
    type Error = pkcs8::spki::Error;
422
423
    fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
424
        PublicKey::try_from(spki).map(|inner| Self { inner })
425
    }
426
}
427
428
#[cfg(feature = "pem")]
429
impl<C> EncodePublicKey for VerifyingKey<C>
430
where
431
    C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
432
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
433
    FieldBytesSize<C>: sec1::ModulusSize,
434
{
435
    fn to_public_key_der(&self) -> pkcs8::spki::Result<pkcs8::Document> {
436
        self.inner.to_public_key_der()
437
    }
438
}
439
440
#[cfg(feature = "pem")]
441
impl<C> FromStr for VerifyingKey<C>
442
where
443
    C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
444
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
445
    FieldBytesSize<C>: sec1::ModulusSize,
446
{
447
    type Err = Error;
448
449
    fn from_str(s: &str) -> Result<Self> {
450
        Self::from_public_key_pem(s).map_err(|_| Error::new())
451
    }
452
}
453
454
#[cfg(all(feature = "pem", feature = "serde"))]
455
impl<C> Serialize for VerifyingKey<C>
456
where
457
    C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
458
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
459
    FieldBytesSize<C>: sec1::ModulusSize,
460
{
461
    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
462
    where
463
        S: ser::Serializer,
464
    {
465
        self.inner.serialize(serializer)
466
    }
467
}
468
469
#[cfg(all(feature = "pem", feature = "serde"))]
470
impl<'de, C> Deserialize<'de> for VerifyingKey<C>
471
where
472
    C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
473
    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
474
    FieldBytesSize<C>: sec1::ModulusSize,
475
{
476
    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
477
    where
478
        D: de::Deserializer<'de>,
479
    {
480
        PublicKey::<C>::deserialize(deserializer).map(Into::into)
481
    }
482
}