1use crate::{
4 hazmat::{DigestPrimitive, VerifyPrimitive},
5 Error, Result, Signature, SignatureSize,
6};
7use core::{cmp::Ordering, fmt::Debug};
8use elliptic_curve::{
9 generic_array::ArrayLength,
10 ops::Reduce,
11 sec1::{self, EncodedPoint, FromEncodedPoint, ToEncodedPoint},
12 AffinePoint, FieldSize, PointCompression, PrimeCurve, ProjectiveArithmetic, PublicKey, Scalar,
13};
14use signature::{
15 digest::{Digest, FixedOutput},
16 hazmat::PrehashVerifier,
17 DigestVerifier, Verifier,
18};
19
20#[cfg(feature = "pkcs8")]
21use elliptic_curve::pkcs8::{self, AssociatedOid, DecodePublicKey};
22
23#[cfg(feature = "pem")]
24use elliptic_curve::pkcs8::EncodePublicKey;
25
26#[cfg(feature = "pem")]
27use core::str::FromStr;
28
29#[cfg(all(feature = "pem", feature = "serde"))]
30#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
31use serdect::serde::{de, ser, Deserialize, Serialize};
32
33#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
47#[derive(Clone, Debug)]
48pub struct VerifyingKey<C>
49where
50 C: PrimeCurve + ProjectiveArithmetic,
51{
52 pub(crate) inner: PublicKey<C>,
53}
54
55impl<C> VerifyingKey<C>
56where
57 C: PrimeCurve + ProjectiveArithmetic,
58 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
59 FieldSize<C>: sec1::ModulusSize,
60{
61 pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
63 PublicKey::from_sec1_bytes(bytes)
64 .map(|pk| Self { inner: pk })
65 .map_err(|_| Error::new())
66 }
67
68 pub fn from_affine(affine: AffinePoint<C>) -> Result<Self> {
73 Ok(Self {
74 inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?,
75 })
76 }
77
78 pub fn from_encoded_point(public_key: &EncodedPoint<C>) -> Result<Self> {
80 Option::from(PublicKey::<C>::from_encoded_point(public_key))
81 .map(|public_key| Self { inner: public_key })
82 .ok_or_else(Error::new)
83 }
84
85 pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
88 self.inner.to_encoded_point(compress)
89 }
90
91 pub fn as_affine(&self) -> &AffinePoint<C> {
93 self.inner.as_affine()
94 }
95}
96
97impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C>
98where
99 C: PrimeCurve + ProjectiveArithmetic,
100 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
101 FieldSize<C>: sec1::ModulusSize,
102{
103 fn as_ref(&self) -> &AffinePoint<C> {
104 self.as_affine()
105 }
106}
107
108impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + ProjectiveArithmetic {}
109
110impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C>
111where
112 C: PrimeCurve + ProjectiveArithmetic,
113 D: Digest + FixedOutput<OutputSize = FieldSize<C>>,
114 AffinePoint<C>: VerifyPrimitive<C>,
115 Scalar<C>: Reduce<C::UInt>,
116 SignatureSize<C>: ArrayLength<u8>,
117{
118 fn verify_digest(&self, msg_digest: D, signature: &Signature<C>) -> Result<()> {
119 self.inner.as_affine().verify_digest(msg_digest, signature)
120 }
121}
122
123impl<C> PrehashVerifier<Signature<C>> for VerifyingKey<C>
124where
125 C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
126 AffinePoint<C>: VerifyPrimitive<C>,
127 Scalar<C>: Reduce<C::UInt>,
128 SignatureSize<C>: ArrayLength<u8>,
129{
130 fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> {
131 let prehash = C::prehash_to_field_bytes(prehash)?;
132 self.inner.as_affine().verify_prehashed(prehash, signature)
133 }
134}
135
136impl<C> Verifier<Signature<C>> for VerifyingKey<C>
137where
138 C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
139 C::Digest: FixedOutput<OutputSize = FieldSize<C>>,
140 AffinePoint<C>: VerifyPrimitive<C>,
141 Scalar<C>: Reduce<C::UInt>,
142 SignatureSize<C>: ArrayLength<u8>,
143{
144 fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> {
145 self.verify_digest(C::Digest::new_with_prefix(msg), signature)
146 }
147}
148
149impl<C> From<&VerifyingKey<C>> for EncodedPoint<C>
150where
151 C: PrimeCurve + ProjectiveArithmetic + PointCompression,
152 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
153 FieldSize<C>: sec1::ModulusSize,
154{
155 fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> {
156 verifying_key.to_encoded_point(C::COMPRESS_POINTS)
157 }
158}
159
160impl<C> From<PublicKey<C>> for VerifyingKey<C>
161where
162 C: PrimeCurve + ProjectiveArithmetic,
163{
164 fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
165 VerifyingKey { inner: public_key }
166 }
167}
168
169impl<C> From<&PublicKey<C>> for VerifyingKey<C>
170where
171 C: PrimeCurve + ProjectiveArithmetic,
172{
173 fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> {
174 (*public_key).into()
175 }
176}
177
178impl<C> From<VerifyingKey<C>> for PublicKey<C>
179where
180 C: PrimeCurve + ProjectiveArithmetic,
181{
182 fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> {
183 verifying_key.inner
184 }
185}
186
187impl<C> From<&VerifyingKey<C>> for PublicKey<C>
188where
189 C: PrimeCurve + ProjectiveArithmetic,
190{
191 fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> {
192 (*verifying_key).into()
193 }
194}
195
196impl<C> Eq for VerifyingKey<C> where C: PrimeCurve + ProjectiveArithmetic {}
197
198impl<C> PartialEq for VerifyingKey<C>
199where
200 C: PrimeCurve + ProjectiveArithmetic,
201{
202 fn eq(&self, other: &Self) -> bool {
203 self.inner.eq(&other.inner)
204 }
205}
206
207impl<C> PartialOrd for VerifyingKey<C>
208where
209 C: PrimeCurve + ProjectiveArithmetic,
210 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
211 FieldSize<C>: sec1::ModulusSize,
212{
213 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
214 self.inner.partial_cmp(&other.inner)
215 }
216}
217
218impl<C> Ord for VerifyingKey<C>
219where
220 C: PrimeCurve + ProjectiveArithmetic,
221 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
222 FieldSize<C>: sec1::ModulusSize,
223{
224 fn cmp(&self, other: &Self) -> Ordering {
225 self.inner.cmp(&other.inner)
226 }
227}
228
229impl<C> TryFrom<&[u8]> for VerifyingKey<C>
230where
231 C: PrimeCurve + ProjectiveArithmetic,
232 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
233 FieldSize<C>: sec1::ModulusSize,
234{
235 type Error = Error;
236
237 fn try_from(bytes: &[u8]) -> Result<Self> {
238 Self::from_sec1_bytes(bytes)
239 }
240}
241
242#[cfg(feature = "pkcs8")]
243#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
244impl<C> TryFrom<pkcs8::SubjectPublicKeyInfo<'_>> for VerifyingKey<C>
245where
246 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
247 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
248 FieldSize<C>: sec1::ModulusSize,
249{
250 type Error = pkcs8::spki::Error;
251
252 fn try_from(spki: pkcs8::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result<Self> {
253 PublicKey::try_from(spki).map(|inner| Self { inner })
254 }
255}
256
257#[cfg(feature = "pkcs8")]
258#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
259impl<C> DecodePublicKey for VerifyingKey<C>
260where
261 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
262 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
263 FieldSize<C>: sec1::ModulusSize,
264{
265}
266
267#[cfg(feature = "pem")]
268#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
269impl<C> EncodePublicKey for VerifyingKey<C>
270where
271 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
272 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
273 FieldSize<C>: sec1::ModulusSize,
274{
275 fn to_public_key_der(&self) -> pkcs8::spki::Result<pkcs8::Document> {
276 self.inner.to_public_key_der()
277 }
278}
279
280#[cfg(feature = "pem")]
281#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
282impl<C> FromStr for VerifyingKey<C>
283where
284 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
285 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
286 FieldSize<C>: sec1::ModulusSize,
287{
288 type Err = Error;
289
290 fn from_str(s: &str) -> Result<Self> {
291 Self::from_public_key_pem(s).map_err(|_| Error::new())
292 }
293}
294
295#[cfg(all(feature = "pem", feature = "serde"))]
296#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
297impl<C> Serialize for VerifyingKey<C>
298where
299 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
300 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
301 FieldSize<C>: sec1::ModulusSize,
302{
303 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
304 where
305 S: ser::Serializer,
306 {
307 self.inner.serialize(serializer)
308 }
309}
310
311#[cfg(all(feature = "pem", feature = "serde"))]
312#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
313impl<'de, C> Deserialize<'de> for VerifyingKey<C>
314where
315 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
316 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
317 FieldSize<C>: sec1::ModulusSize,
318{
319 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
320 where
321 D: de::Deserializer<'de>,
322 {
323 PublicKey::<C>::deserialize(deserializer).map(Into::into)
324 }
325}