1use crate::{
4 hazmat::{bits2field, DigestPrimitive, VerifyPrimitive},
5 Error, Result, Signature, SignatureSize,
6};
7use core::{cmp::Ordering, fmt::Debug};
8use elliptic_curve::{
9 generic_array::ArrayLength,
10 point::PointCompression,
11 sec1::{self, CompressedPoint, EncodedPoint, FromEncodedPoint, ToEncodedPoint},
12 AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey,
13};
14use signature::{
15 digest::{Digest, FixedOutput},
16 hazmat::PrehashVerifier,
17 DigestVerifier, Verifier,
18};
19
20#[cfg(feature = "alloc")]
21use alloc::boxed::Box;
22
23#[cfg(feature = "der")]
24use {crate::der, core::ops::Add};
25
26#[cfg(feature = "pem")]
27use {
28 core::str::FromStr,
29 elliptic_curve::pkcs8::{DecodePublicKey, EncodePublicKey},
30};
31
32#[cfg(feature = "pkcs8")]
33use elliptic_curve::pkcs8::{
34 self,
35 der::AnyRef,
36 spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
37 AssociatedOid, ObjectIdentifier,
38};
39
40#[cfg(feature = "sha2")]
41use {
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"))]
49use serdect::serde::{de, ser, Deserialize, Serialize};
50
51#[derive(Clone, Debug)]
78pub struct VerifyingKey<C>
79where
80 C: PrimeCurve + CurveArithmetic,
81{
82 pub(crate) inner: PublicKey<C>,
83}
84
85impl<C> VerifyingKey<C>
86where
87 C: PrimeCurve + CurveArithmetic,
88 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
89 FieldBytesSize<C>: sec1::ModulusSize,
90{
91 pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
93 PublicKey::from_sec1_bytes(bytes)
94 .map(|pk| Self { inner: pk })
95 .map_err(|_| Error::new())
96 }
97
98 pub fn from_affine(affine: AffinePoint<C>) -> Result<Self> {
103 Ok(Self {
104 inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?,
105 })
106 }
107
108 pub fn from_encoded_point(public_key: &EncodedPoint<C>) -> Result<Self> {
110 Option::from(PublicKey::<C>::from_encoded_point(public_key))
111 .map(|public_key| Self { inner: public_key })
112 .ok_or_else(Error::new)
113 }
114
115 pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
118 self.inner.to_encoded_point(compress)
119 }
120
121 #[cfg(feature = "alloc")]
128 pub fn to_sec1_bytes(&self) -> Box<[u8]>
129 where
130 C: PointCompression,
131 {
132 self.inner.to_sec1_bytes()
133 }
134
135 pub fn as_affine(&self) -> &AffinePoint<C> {
137 self.inner.as_affine()
138 }
139}
140
141impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C>
146where
147 C: PrimeCurve + CurveArithmetic,
148 D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
149 AffinePoint<C>: VerifyPrimitive<C>,
150 SignatureSize<C>: ArrayLength<u8>,
151{
152 fn verify_digest(&self, msg_digest: D, signature: &Signature<C>) -> Result<()> {
153 self.inner.as_affine().verify_digest(msg_digest, signature)
154 }
155}
156
157impl<C> PrehashVerifier<Signature<C>> for VerifyingKey<C>
158where
159 C: PrimeCurve + CurveArithmetic,
160 AffinePoint<C>: VerifyPrimitive<C>,
161 SignatureSize<C>: ArrayLength<u8>,
162{
163 fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> {
164 let field = bits2field::<C>(prehash)?;
165 self.inner.as_affine().verify_prehashed(&field, signature)
166 }
167}
168
169impl<C> Verifier<Signature<C>> for VerifyingKey<C>
170where
171 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
172 AffinePoint<C>: VerifyPrimitive<C>,
173 SignatureSize<C>: ArrayLength<u8>,
174{
175 fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> {
176 self.verify_digest(C::Digest::new_with_prefix(msg), signature)
177 }
178}
179
180#[cfg(feature = "sha2")]
181impl<C> Verifier<SignatureWithOid<C>> for VerifyingKey<C>
182where
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")]
199impl<C, D> DigestVerifier<D, der::Signature<C>> for VerifyingKey<C>
200where
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 fn verify_digest(&self, msg_digest: D, signature: &der::Signature<C>) -> Result<()> {
209 let signature = Signature::<C>::try_from(signature.clone())?;
210 DigestVerifier::<D, Signature<C>>::verify_digest(self, msg_digest, &signature)
211 }
212}
213
214#[cfg(feature = "der")]
215impl<C> PrehashVerifier<der::Signature<C>> for VerifyingKey<C>
216where
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 fn verify_prehash(&self, prehash: &[u8], signature: &der::Signature<C>) -> Result<()> {
224 let signature = Signature::<C>::try_from(signature.clone())?;
225 PrehashVerifier::<Signature<C>>::verify_prehash(self, prehash, &signature)
226 }
227}
228
229#[cfg(feature = "der")]
230impl<C> Verifier<der::Signature<C>> for VerifyingKey<C>
231where
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 fn verify(&self, msg: &[u8], signature: &der::Signature<C>) -> Result<()> {
239 let signature = Signature::<C>::try_from(signature.clone())?;
240 Verifier::<Signature<C>>::verify(self, msg, &signature)
241 }
242}
243
244impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C>
249where
250 C: PrimeCurve + CurveArithmetic,
251 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
252 FieldBytesSize<C>: sec1::ModulusSize,
253{
254 fn as_ref(&self) -> &AffinePoint<C> {
255 self.as_affine()
256 }
257}
258
259impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {}
260
261impl<C> From<VerifyingKey<C>> for CompressedPoint<C>
262where
263 C: PrimeCurve + CurveArithmetic + PointCompression,
264 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
265 FieldBytesSize<C>: sec1::ModulusSize,
266{
267 fn from(verifying_key: VerifyingKey<C>) -> CompressedPoint<C> {
268 verifying_key.inner.into()
269 }
270}
271
272impl<C> From<&VerifyingKey<C>> for CompressedPoint<C>
273where
274 C: PrimeCurve + CurveArithmetic + PointCompression,
275 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
276 FieldBytesSize<C>: sec1::ModulusSize,
277{
278 fn from(verifying_key: &VerifyingKey<C>) -> CompressedPoint<C> {
279 verifying_key.inner.into()
280 }
281}
282
283impl<C> From<VerifyingKey<C>> for EncodedPoint<C>
284where
285 C: PrimeCurve + CurveArithmetic + PointCompression,
286 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
287 FieldBytesSize<C>: sec1::ModulusSize,
288{
289 fn from(verifying_key: VerifyingKey<C>) -> EncodedPoint<C> {
290 verifying_key.inner.into()
291 }
292}
293
294impl<C> From<&VerifyingKey<C>> for EncodedPoint<C>
295where
296 C: PrimeCurve + CurveArithmetic + PointCompression,
297 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
298 FieldBytesSize<C>: sec1::ModulusSize,
299{
300 fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> {
301 verifying_key.inner.into()
302 }
303}
304
305impl<C> Eq for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {}
306
307impl<C> PartialEq for VerifyingKey<C>
308where
309 C: PrimeCurve + CurveArithmetic,
310{
311 fn eq(&self, other: &Self) -> bool {
312 self.inner.eq(&other.inner)
313 }
314}
315
316impl<C> From<PublicKey<C>> for VerifyingKey<C>
317where
318 C: PrimeCurve + CurveArithmetic,
319{
320 fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
321 VerifyingKey { inner: public_key }
322 }
323}
324
325impl<C> From<&PublicKey<C>> for VerifyingKey<C>
326where
327 C: PrimeCurve + CurveArithmetic,
328{
329 fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> {
330 (*public_key).into()
331 }
332}
333
334impl<C> From<VerifyingKey<C>> for PublicKey<C>
335where
336 C: PrimeCurve + CurveArithmetic,
337{
338 fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> {
339 verifying_key.inner
340 }
341}
342
343impl<C> From<&VerifyingKey<C>> for PublicKey<C>
344where
345 C: PrimeCurve + CurveArithmetic,
346{
347 fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> {
348 (*verifying_key).into()
349 }
350}
351
352impl<C> PartialOrd for VerifyingKey<C>
353where
354 C: PrimeCurve + CurveArithmetic,
355 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
356 FieldBytesSize<C>: sec1::ModulusSize,
357{
358 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
359 self.inner.partial_cmp(&other.inner)
360 }
361}
362
363impl<C> Ord for VerifyingKey<C>
364where
365 C: PrimeCurve + CurveArithmetic,
366 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
367 FieldBytesSize<C>: sec1::ModulusSize,
368{
369 fn cmp(&self, other: &Self) -> Ordering {
370 self.inner.cmp(&other.inner)
371 }
372}
373
374impl<C> TryFrom<&[u8]> for VerifyingKey<C>
375where
376 C: PrimeCurve + CurveArithmetic,
377 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
378 FieldBytesSize<C>: sec1::ModulusSize,
379{
380 type Error = Error;
381
382 fn try_from(bytes: &[u8]) -> Result<Self> {
383 Self::from_sec1_bytes(bytes)
384 }
385}
386
387#[cfg(feature = "pkcs8")]
388impl<C> AssociatedAlgorithmIdentifier for VerifyingKey<C>
389where
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")]
401impl<C> SignatureAlgorithmIdentifier for VerifyingKey<C>
402where
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")]
415impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<C>
416where
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")]
429impl<C> EncodePublicKey for VerifyingKey<C>
430where
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")]
441impl<C> FromStr for VerifyingKey<C>
442where
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"))]
455impl<C> Serialize for VerifyingKey<C>
456where
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"))]
470impl<'de, C> Deserialize<'de> for VerifyingKey<C>
471where
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}