ecdsa_flow/
verify.rs

1//! ECDSA verification key.
2
3use crate::{
4    hazmat::{DigestPrimitive, FromDigest, VerifyPrimitive},
5    Error, Result, Signature, SignatureSize,
6};
7use core::{cmp::Ordering, convert::TryFrom, fmt::Debug, ops::Add};
8use elliptic_curve_flow::{
9    consts::U1,
10    generic_array::ArrayLength,
11    sec1::{
12        EncodedPoint, FromEncodedPoint, ToEncodedPoint, UncompressedPointSize, UntaggedPointSize,
13    },
14    AffinePoint, FieldSize, PointCompression, PrimeCurve, ProjectiveArithmetic, PublicKey, Scalar,
15};
16use signature_flow::{digest::Digest, DigestVerifier, Verifier};
17
18#[cfg(feature = "pkcs8")]
19use crate::elliptic_curve_flow::{
20    pkcs8::{self, FromPublicKey},
21    AlgorithmParameters,
22};
23
24#[cfg(feature = "pem")]
25use core::str::FromStr;
26
27/// ECDSA verification key (i.e. public key). Generic over elliptic curves.
28///
29/// Requires an [`elliptic_curve_flow::ProjectiveArithmetic`] impl on the curve, and a
30/// [`VerifyPrimitive`] impl on its associated `AffinePoint` type.
31#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
32#[derive(Clone, Debug)]
33pub struct VerifyingKey<C>
34where
35    C: PrimeCurve + ProjectiveArithmetic,
36{
37    pub(crate) inner: PublicKey<C>,
38}
39
40impl<C> VerifyingKey<C>
41where
42    C: PrimeCurve + ProjectiveArithmetic,
43    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
44    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
45    UncompressedPointSize<C>: ArrayLength<u8>,
46{
47    /// Initialize [`VerifyingKey`] from a SEC1-encoded public key.
48    pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
49        PublicKey::from_sec1_bytes(bytes)
50            .map(|pk| Self { inner: pk })
51            .map_err(|_| Error::new())
52    }
53
54    /// Initialize [`VerifyingKey`] from an [`EncodedPoint`].
55    pub fn from_encoded_point(public_key: &EncodedPoint<C>) -> Result<Self> {
56        PublicKey::<C>::from_encoded_point(public_key)
57            .map(|public_key| Self { inner: public_key })
58            .ok_or_else(Error::new)
59    }
60
61    /// Serialize this [`VerifyingKey`] as a SEC1 [`EncodedPoint`], optionally
62    /// applying point compression.
63    pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
64        self.inner.to_encoded_point(compress)
65    }
66}
67
68impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + ProjectiveArithmetic {}
69
70impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C>
71where
72    C: PrimeCurve + ProjectiveArithmetic,
73    D: Digest<OutputSize = FieldSize<C>>,
74    AffinePoint<C>: VerifyPrimitive<C>,
75    Scalar<C>: FromDigest<C>,
76    SignatureSize<C>: ArrayLength<u8>,
77{
78    fn verify_digest(&self, digest: D, signature: &Signature<C>) -> Result<()> {
79        self.inner
80            .as_affine()
81            .verify_prehashed(&Scalar::<C>::from_digest(digest), signature)
82    }
83}
84
85impl<C> Verifier<Signature<C>> for VerifyingKey<C>
86where
87    C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
88    C::Digest: Digest<OutputSize = FieldSize<C>>,
89    AffinePoint<C>: VerifyPrimitive<C>,
90    Scalar<C>: FromDigest<C>,
91    SignatureSize<C>: ArrayLength<u8>,
92{
93    fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> {
94        self.verify_digest(C::Digest::new().chain(msg), signature)
95    }
96}
97
98impl<C> From<&VerifyingKey<C>> for EncodedPoint<C>
99where
100    C: PrimeCurve + ProjectiveArithmetic + PointCompression,
101    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
102    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
103    UncompressedPointSize<C>: ArrayLength<u8>,
104{
105    fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> {
106        verifying_key.to_encoded_point(C::COMPRESS_POINTS)
107    }
108}
109
110impl<C> From<PublicKey<C>> for VerifyingKey<C>
111where
112    C: PrimeCurve + ProjectiveArithmetic,
113{
114    fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
115        VerifyingKey { inner: public_key }
116    }
117}
118
119impl<C> From<&PublicKey<C>> for VerifyingKey<C>
120where
121    C: PrimeCurve + ProjectiveArithmetic,
122{
123    fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> {
124        public_key.clone().into()
125    }
126}
127
128impl<C> From<VerifyingKey<C>> for PublicKey<C>
129where
130    C: PrimeCurve + ProjectiveArithmetic,
131{
132    fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> {
133        verifying_key.inner
134    }
135}
136
137impl<C> From<&VerifyingKey<C>> for PublicKey<C>
138where
139    C: PrimeCurve + ProjectiveArithmetic,
140{
141    fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> {
142        verifying_key.clone().into()
143    }
144}
145
146impl<C> Eq for VerifyingKey<C>
147where
148    C: PrimeCurve + ProjectiveArithmetic,
149    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
150    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
151    UncompressedPointSize<C>: ArrayLength<u8>,
152{
153}
154
155impl<C> PartialEq for VerifyingKey<C>
156where
157    C: PrimeCurve + ProjectiveArithmetic,
158    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
159    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
160    UncompressedPointSize<C>: ArrayLength<u8>,
161{
162    fn eq(&self, other: &Self) -> bool {
163        self.inner.eq(&other.inner)
164    }
165}
166
167impl<C> PartialOrd for VerifyingKey<C>
168where
169    C: PrimeCurve + ProjectiveArithmetic,
170    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
171    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
172    UncompressedPointSize<C>: ArrayLength<u8>,
173{
174    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
175        self.inner.partial_cmp(&other.inner)
176    }
177}
178
179impl<C> Ord for VerifyingKey<C>
180where
181    C: PrimeCurve + ProjectiveArithmetic,
182    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
183    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
184    UncompressedPointSize<C>: ArrayLength<u8>,
185{
186    fn cmp(&self, other: &Self) -> Ordering {
187        self.inner.cmp(&other.inner)
188    }
189}
190
191impl<C> TryFrom<&[u8]> for VerifyingKey<C>
192where
193    C: PrimeCurve + ProjectiveArithmetic,
194    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
195    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
196    UncompressedPointSize<C>: ArrayLength<u8>,
197{
198    type Error = Error;
199
200    fn try_from(bytes: &[u8]) -> Result<Self> {
201        Self::from_sec1_bytes(bytes)
202    }
203}
204
205#[cfg(feature = "pkcs8")]
206#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
207impl<C> FromPublicKey for VerifyingKey<C>
208where
209    C: PrimeCurve + AlgorithmParameters + ProjectiveArithmetic + PointCompression,
210    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
211    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
212    UncompressedPointSize<C>: ArrayLength<u8>,
213{
214    fn from_spki(spki: pkcs8::SubjectPublicKeyInfo<'_>) -> pkcs8::Result<Self> {
215        PublicKey::from_spki(spki).map(|inner| Self { inner })
216    }
217}
218
219#[cfg(feature = "pem")]
220#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
221impl<C> FromStr for VerifyingKey<C>
222where
223    C: PrimeCurve + AlgorithmParameters + ProjectiveArithmetic + PointCompression,
224    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
225    UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
226    UncompressedPointSize<C>: ArrayLength<u8>,
227{
228    type Err = Error;
229
230    fn from_str(s: &str) -> Result<Self> {
231        Self::from_public_key_pem(s).map_err(|_| Error::new())
232    }
233}