1use crate::{DigestAlgorithm, EcdsaCurve, Error, Result, Signature, hazmat};
4use core::{cmp::Ordering, fmt::Debug};
5use digest::{Digest, Update};
6use elliptic_curve::{
7 AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey,
8 point::PointCompression,
9 sec1::{self, CompressedPoint, FromSec1Point, Sec1Point, ToSec1Point},
10};
11use signature::{DigestVerifier, MultipartVerifier, Verifier, hazmat::PrehashVerifier};
12
13#[cfg(feature = "alloc")]
14use alloc::boxed::Box;
15#[cfg(all(feature = "alloc", feature = "pkcs8"))]
16use elliptic_curve::pkcs8::EncodePublicKey;
17#[cfg(feature = "pkcs8")]
18use elliptic_curve::pkcs8::{
19 self, AssociatedOid, ObjectIdentifier,
20 der::AnyRef,
21 spki::{
22 self, AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier,
23 },
24};
25#[cfg(feature = "serde")]
26use serdect::serde::{Deserialize, Serialize, de, ser};
27#[cfg(feature = "der")]
28use {crate::der, core::ops::Add, elliptic_curve::array::ArraySize};
29#[cfg(feature = "sha2")]
30use {
31 crate::{
32 ECDSA_SHA224_OID, ECDSA_SHA256_OID, ECDSA_SHA384_OID, ECDSA_SHA512_OID, SignatureWithOid,
33 },
34 sha2::{Sha224, Sha256, Sha384, Sha512},
35};
36#[cfg(feature = "pem")]
37use {core::str::FromStr, elliptic_curve::pkcs8::DecodePublicKey};
38
39#[derive(Clone, Debug)]
65pub struct VerifyingKey<C>
66where
67 C: EcdsaCurve + CurveArithmetic,
68{
69 pub(crate) inner: PublicKey<C>,
70}
71
72impl<C> VerifyingKey<C>
73where
74 C: EcdsaCurve + CurveArithmetic,
75 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
76 FieldBytesSize<C>: sec1::ModulusSize,
77{
78 pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
85 PublicKey::from_sec1_bytes(bytes)
86 .map(|pk| Self { inner: pk })
87 .map_err(|_| Error::new())
88 }
89
90 pub fn from_affine(affine: AffinePoint<C>) -> Result<Self> {
95 Ok(Self {
96 inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?,
97 })
98 }
99
100 pub fn from_sec1_point(public_key: &Sec1Point<C>) -> Result<Self> {
105 PublicKey::<C>::from_sec1_point(public_key)
106 .into_option()
107 .map(|public_key| Self { inner: public_key })
108 .ok_or_else(Error::new)
109 }
110
111 pub fn to_sec1_point(&self, compress: bool) -> Sec1Point<C> {
114 self.inner.to_sec1_point(compress)
115 }
116
117 #[cfg(feature = "alloc")]
124 pub fn to_sec1_bytes(&self) -> Box<[u8]>
125 where
126 C: PointCompression,
127 {
128 self.inner.to_sec1_bytes()
129 }
130
131 pub fn as_affine(&self) -> &AffinePoint<C> {
133 self.inner.as_affine()
134 }
135}
136
137impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C>
142where
143 C: EcdsaCurve + CurveArithmetic,
144 D: Digest + Update,
145{
146 fn verify_digest<F: Fn(&mut D) -> Result<()>>(
147 &self,
148 f: F,
149 signature: &Signature<C>,
150 ) -> Result<()> {
151 let mut digest = D::new();
152 f(&mut digest)?;
153 self.verify_prehash(&digest.finalize(), signature)
154 }
155}
156
157impl<C> PrehashVerifier<Signature<C>> for VerifyingKey<C>
158where
159 C: EcdsaCurve + CurveArithmetic,
160{
161 fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> {
162 hazmat::verify_prehashed::<C>(&(*self.inner.as_affine()).into(), prehash, signature)
163 }
164}
165
166impl<C> Verifier<Signature<C>> for VerifyingKey<C>
167where
168 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
169{
170 fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> {
171 self.multipart_verify(&[msg], signature)
172 }
173}
174
175impl<C> MultipartVerifier<Signature<C>> for VerifyingKey<C>
176where
177 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
178{
179 fn multipart_verify(&self, msg: &[&[u8]], signature: &Signature<C>) -> Result<()> {
180 self.verify_digest(
181 |digest: &mut C::Digest| {
182 msg.iter().for_each(|slice| Update::update(digest, slice));
183 Ok(())
184 },
185 signature,
186 )
187 }
188}
189
190#[cfg(feature = "sha2")]
191impl<C> Verifier<SignatureWithOid<C>> for VerifyingKey<C>
192where
193 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
194{
195 fn verify(&self, msg: &[u8], sig: &SignatureWithOid<C>) -> Result<()> {
196 self.multipart_verify(&[msg], sig)
197 }
198}
199
200#[cfg(feature = "sha2")]
201impl<C> MultipartVerifier<SignatureWithOid<C>> for VerifyingKey<C>
202where
203 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
204{
205 fn multipart_verify(&self, msg: &[&[u8]], sig: &SignatureWithOid<C>) -> Result<()> {
206 match sig.oid() {
207 ECDSA_SHA224_OID => {
208 let mut digest = Sha224::default();
209 msg.iter()
210 .for_each(|slice| Update::update(&mut digest, slice));
211 self.verify_prehash(&digest.finalize(), sig.signature())
212 }
213 ECDSA_SHA256_OID => {
214 let mut digest = Sha256::default();
215 msg.iter()
216 .for_each(|slice| Update::update(&mut digest, slice));
217 self.verify_prehash(&digest.finalize(), sig.signature())
218 }
219 ECDSA_SHA384_OID => {
220 let mut digest = Sha384::default();
221 msg.iter()
222 .for_each(|slice| Update::update(&mut digest, slice));
223 self.verify_prehash(&digest.finalize(), sig.signature())
224 }
225 ECDSA_SHA512_OID => {
226 let mut digest = Sha512::default();
227 msg.iter()
228 .for_each(|slice| Update::update(&mut digest, slice));
229 self.verify_prehash(&digest.finalize(), sig.signature())
230 }
231 _ => Err(Error::new()),
232 }
233 }
234}
235
236#[cfg(feature = "der")]
237impl<C, D> DigestVerifier<D, der::Signature<C>> for VerifyingKey<C>
238where
239 C: EcdsaCurve + CurveArithmetic,
240 D: Digest + Update,
241 der::MaxSize<C>: ArraySize,
242 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
243{
244 fn verify_digest<F: Fn(&mut D) -> Result<()>>(
245 &self,
246 f: F,
247 signature: &der::Signature<C>,
248 ) -> Result<()> {
249 let signature = Signature::<C>::try_from(signature.clone())?;
250 DigestVerifier::<D, Signature<C>>::verify_digest(self, f, &signature)
251 }
252}
253
254#[cfg(feature = "der")]
255impl<C> PrehashVerifier<der::Signature<C>> for VerifyingKey<C>
256where
257 C: EcdsaCurve + CurveArithmetic,
258 der::MaxSize<C>: ArraySize,
259 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
260{
261 fn verify_prehash(&self, prehash: &[u8], signature: &der::Signature<C>) -> Result<()> {
262 let signature = Signature::<C>::try_from(signature.clone())?;
263 PrehashVerifier::<Signature<C>>::verify_prehash(self, prehash, &signature)
264 }
265}
266
267#[cfg(feature = "der")]
268impl<C> Verifier<der::Signature<C>> for VerifyingKey<C>
269where
270 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
271 der::MaxSize<C>: ArraySize,
272 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
273{
274 fn verify(&self, msg: &[u8], signature: &der::Signature<C>) -> Result<()> {
275 let signature = Signature::<C>::try_from(signature.clone())?;
276 Verifier::<Signature<C>>::verify(self, msg, &signature)
277 }
278}
279
280#[cfg(feature = "der")]
281impl<C> MultipartVerifier<der::Signature<C>> for VerifyingKey<C>
282where
283 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
284 der::MaxSize<C>: ArraySize,
285 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
286{
287 fn multipart_verify(&self, msg: &[&[u8]], signature: &der::Signature<C>) -> Result<()> {
288 let signature = Signature::<C>::try_from(signature.clone())?;
289 MultipartVerifier::<Signature<C>>::multipart_verify(self, msg, &signature)
290 }
291}
292
293impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C>
298where
299 C: EcdsaCurve + CurveArithmetic,
300 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
301 FieldBytesSize<C>: sec1::ModulusSize,
302{
303 fn as_ref(&self) -> &AffinePoint<C> {
304 self.as_affine()
305 }
306}
307
308impl<C> Copy for VerifyingKey<C> where C: EcdsaCurve + CurveArithmetic {}
309
310impl<C> From<VerifyingKey<C>> for CompressedPoint<C>
311where
312 C: EcdsaCurve + CurveArithmetic + PointCompression,
313 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
314 FieldBytesSize<C>: sec1::ModulusSize,
315{
316 fn from(verifying_key: VerifyingKey<C>) -> CompressedPoint<C> {
317 verifying_key.inner.into()
318 }
319}
320
321impl<C> From<&VerifyingKey<C>> for CompressedPoint<C>
322where
323 C: EcdsaCurve + CurveArithmetic + PointCompression,
324 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
325 FieldBytesSize<C>: sec1::ModulusSize,
326{
327 fn from(verifying_key: &VerifyingKey<C>) -> CompressedPoint<C> {
328 verifying_key.inner.into()
329 }
330}
331
332impl<C> From<VerifyingKey<C>> for Sec1Point<C>
333where
334 C: EcdsaCurve + CurveArithmetic + PointCompression,
335 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
336 FieldBytesSize<C>: sec1::ModulusSize,
337{
338 fn from(verifying_key: VerifyingKey<C>) -> Sec1Point<C> {
339 verifying_key.inner.into()
340 }
341}
342
343impl<C> From<&VerifyingKey<C>> for Sec1Point<C>
344where
345 C: EcdsaCurve + CurveArithmetic + PointCompression,
346 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
347 FieldBytesSize<C>: sec1::ModulusSize,
348{
349 fn from(verifying_key: &VerifyingKey<C>) -> Sec1Point<C> {
350 verifying_key.inner.into()
351 }
352}
353
354impl<C> Eq for VerifyingKey<C> where C: EcdsaCurve + CurveArithmetic {}
355
356impl<C> PartialEq for VerifyingKey<C>
357where
358 C: EcdsaCurve + CurveArithmetic,
359{
360 fn eq(&self, other: &Self) -> bool {
361 self.inner.eq(&other.inner)
362 }
363}
364
365impl<C> From<PublicKey<C>> for VerifyingKey<C>
366where
367 C: EcdsaCurve + CurveArithmetic,
368{
369 fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
370 VerifyingKey { inner: public_key }
371 }
372}
373
374impl<C> From<&PublicKey<C>> for VerifyingKey<C>
375where
376 C: EcdsaCurve + CurveArithmetic,
377{
378 fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> {
379 (*public_key).into()
380 }
381}
382
383impl<C> From<VerifyingKey<C>> for PublicKey<C>
384where
385 C: EcdsaCurve + CurveArithmetic,
386{
387 fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> {
388 verifying_key.inner
389 }
390}
391
392impl<C> From<&VerifyingKey<C>> for PublicKey<C>
393where
394 C: EcdsaCurve + CurveArithmetic,
395{
396 fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> {
397 (*verifying_key).into()
398 }
399}
400
401impl<C> PartialOrd for VerifyingKey<C>
402where
403 C: EcdsaCurve + CurveArithmetic,
404 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
405 FieldBytesSize<C>: sec1::ModulusSize,
406{
407 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
408 Some(self.cmp(other))
409 }
410}
411
412impl<C> Ord for VerifyingKey<C>
413where
414 C: EcdsaCurve + CurveArithmetic,
415 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
416 FieldBytesSize<C>: sec1::ModulusSize,
417{
418 fn cmp(&self, other: &Self) -> Ordering {
419 self.inner.cmp(&other.inner)
420 }
421}
422
423impl<C> TryFrom<&[u8]> for VerifyingKey<C>
424where
425 C: EcdsaCurve + CurveArithmetic,
426 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
427 FieldBytesSize<C>: sec1::ModulusSize,
428{
429 type Error = Error;
430
431 fn try_from(bytes: &[u8]) -> Result<Self> {
432 Self::from_sec1_bytes(bytes)
433 }
434}
435
436#[cfg(feature = "pkcs8")]
437impl<C> AssociatedAlgorithmIdentifier for VerifyingKey<C>
438where
439 C: EcdsaCurve + AssociatedOid + CurveArithmetic,
440 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
441 FieldBytesSize<C>: sec1::ModulusSize,
442{
443 type Params = ObjectIdentifier;
444
445 const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> =
446 PublicKey::<C>::ALGORITHM_IDENTIFIER;
447}
448
449#[cfg(feature = "pkcs8")]
450impl<C> SignatureAlgorithmIdentifier for VerifyingKey<C>
451where
452 C: EcdsaCurve + CurveArithmetic,
453 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
454 FieldBytesSize<C>: sec1::ModulusSize,
455 Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
456{
457 type Params = AnyRef<'static>;
458
459 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
460 Signature::<C>::ALGORITHM_IDENTIFIER;
461}
462
463#[cfg(feature = "pkcs8")]
464impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<C>
465where
466 C: EcdsaCurve + AssociatedOid + CurveArithmetic + PointCompression,
467 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
468 FieldBytesSize<C>: sec1::ModulusSize,
469{
470 type Error = spki::Error;
471
472 fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> spki::Result<Self> {
473 PublicKey::try_from(spki).map(|inner| Self { inner })
474 }
475}
476
477#[cfg(all(feature = "alloc", feature = "pkcs8"))]
478impl<C> EncodePublicKey for VerifyingKey<C>
479where
480 C: EcdsaCurve + AssociatedOid + CurveArithmetic + PointCompression,
481 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
482 FieldBytesSize<C>: sec1::ModulusSize,
483{
484 fn to_public_key_der(&self) -> spki::Result<pkcs8::Document> {
485 self.inner.to_public_key_der()
486 }
487}
488
489#[cfg(feature = "pem")]
490impl<C> FromStr for VerifyingKey<C>
491where
492 C: EcdsaCurve + AssociatedOid + CurveArithmetic + PointCompression,
493 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
494 FieldBytesSize<C>: sec1::ModulusSize,
495{
496 type Err = Error;
497
498 fn from_str(s: &str) -> Result<Self> {
499 Self::from_public_key_pem(s).map_err(|_| Error::new())
500 }
501}
502
503#[cfg(feature = "serde")]
504impl<C> Serialize for VerifyingKey<C>
505where
506 C: EcdsaCurve + AssociatedOid + CurveArithmetic + PointCompression,
507 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
508 FieldBytesSize<C>: sec1::ModulusSize,
509{
510 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
511 where
512 S: ser::Serializer,
513 {
514 self.inner.serialize(serializer)
515 }
516}
517
518#[cfg(feature = "serde")]
519impl<'de, C> Deserialize<'de> for VerifyingKey<C>
520where
521 C: EcdsaCurve + AssociatedOid + CurveArithmetic + PointCompression,
522 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
523 FieldBytesSize<C>: sec1::ModulusSize,
524{
525 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
526 where
527 D: de::Deserializer<'de>,
528 {
529 PublicKey::<C>::deserialize(deserializer).map(Into::into)
530 }
531}