1use crate::{Algorithm, EcdsaCurve, Error, Result};
4use core::fmt;
5use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
6use sec1::consts::{U32, U48, U66};
7
8pub(super) type EcdsaNistP256PublicKey = sec1::EncodedPoint<U32>;
10
11pub(super) type EcdsaNistP384PublicKey = sec1::EncodedPoint<U48>;
13
14pub(super) type EcdsaNistP521PublicKey = sec1::EncodedPoint<U66>;
16
17#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
24pub enum EcdsaPublicKey {
25 NistP256(EcdsaNistP256PublicKey),
27
28 NistP384(EcdsaNistP384PublicKey),
30
31 NistP521(EcdsaNistP521PublicKey),
33}
34
35impl EcdsaPublicKey {
36 const MAX_SIZE: usize = 133;
42
43 pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
50 match bytes {
51 [tag, rest @ ..] => {
52 let point_size = match sec1::point::Tag::from_u8(*tag)? {
53 sec1::point::Tag::CompressedEvenY | sec1::point::Tag::CompressedOddY => {
54 rest.len()
55 }
56 #[allow(clippy::integer_division_remainder_used, reason = "public input")]
57 sec1::point::Tag::Uncompressed => rest.len() / 2,
58 _ => return Err(Error::FormatEncoding),
59 };
60
61 match point_size {
62 32 => Ok(Self::NistP256(EcdsaNistP256PublicKey::from_bytes(bytes)?)),
63 48 => Ok(Self::NistP384(EcdsaNistP384PublicKey::from_bytes(bytes)?)),
64 66 => Ok(Self::NistP521(EcdsaNistP521PublicKey::from_bytes(bytes)?)),
65 _ => Err(encoding::Error::Length.into()),
66 }
67 }
68 _ => Err(encoding::Error::Length.into()),
69 }
70 }
71
72 #[must_use]
74 pub fn as_sec1_bytes(&self) -> &[u8] {
75 match self {
76 EcdsaPublicKey::NistP256(point) => point.as_bytes(),
77 EcdsaPublicKey::NistP384(point) => point.as_bytes(),
78 EcdsaPublicKey::NistP521(point) => point.as_bytes(),
79 }
80 }
81
82 #[must_use]
84 pub fn algorithm(&self) -> Algorithm {
85 Algorithm::Ecdsa {
86 curve: self.curve(),
87 }
88 }
89
90 #[must_use]
92 pub fn curve(&self) -> EcdsaCurve {
93 match self {
94 EcdsaPublicKey::NistP256(_) => EcdsaCurve::NistP256,
95 EcdsaPublicKey::NistP384(_) => EcdsaCurve::NistP384,
96 EcdsaPublicKey::NistP521(_) => EcdsaCurve::NistP521,
97 }
98 }
99}
100
101impl AsRef<[u8]> for EcdsaPublicKey {
102 fn as_ref(&self) -> &[u8] {
103 self.as_sec1_bytes()
104 }
105}
106
107impl Decode for EcdsaPublicKey {
108 type Error = Error;
109
110 fn decode(reader: &mut impl Reader) -> Result<Self> {
111 let curve = EcdsaCurve::decode(reader)?;
112
113 let mut buf = [0u8; Self::MAX_SIZE];
114 let key = Self::from_sec1_bytes(reader.read_byten(&mut buf)?)?;
115
116 if key.curve() == curve {
117 Ok(key)
118 } else {
119 Err(Error::AlgorithmUnknown)
120 }
121 }
122}
123
124impl Encode for EcdsaPublicKey {
125 fn encoded_len(&self) -> encoding::Result<usize> {
126 [
127 self.curve().encoded_len()?,
128 4, self.as_ref().len(),
130 ]
131 .checked_sum()
132 }
133
134 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
135 self.curve().encode(writer)?;
136 self.as_ref().encode(writer)?;
137 Ok(())
138 }
139}
140
141impl fmt::Display for EcdsaPublicKey {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 write!(f, "{self:X}")
144 }
145}
146
147impl fmt::LowerHex for EcdsaPublicKey {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 for byte in self.as_sec1_bytes() {
150 write!(f, "{byte:02x}")?;
151 }
152 Ok(())
153 }
154}
155
156impl fmt::UpperHex for EcdsaPublicKey {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 for byte in self.as_sec1_bytes() {
159 write!(f, "{byte:02X}")?;
160 }
161 Ok(())
162 }
163}
164
165macro_rules! impl_ecdsa_for_curve {
166 ($krate:ident, $feature:expr, $curve:ident) => {
167 #[cfg(feature = $feature)]
168 impl TryFrom<EcdsaPublicKey> for $krate::ecdsa::VerifyingKey {
169 type Error = Error;
170
171 fn try_from(key: EcdsaPublicKey) -> Result<$krate::ecdsa::VerifyingKey> {
172 $krate::ecdsa::VerifyingKey::try_from(&key)
173 }
174 }
175
176 #[cfg(feature = $feature)]
177 impl TryFrom<&EcdsaPublicKey> for $krate::ecdsa::VerifyingKey {
178 type Error = Error;
179
180 fn try_from(public_key: &EcdsaPublicKey) -> Result<$krate::ecdsa::VerifyingKey> {
181 match public_key {
182 EcdsaPublicKey::$curve(key) => {
183 $krate::ecdsa::VerifyingKey::from_sec1_point(key).map_err(|_| Error::Crypto)
184 }
185 _ => Err(Error::AlgorithmUnknown),
186 }
187 }
188 }
189
190 #[cfg(feature = $feature)]
191 impl From<$krate::ecdsa::VerifyingKey> for EcdsaPublicKey {
192 fn from(key: $krate::ecdsa::VerifyingKey) -> EcdsaPublicKey {
193 EcdsaPublicKey::from(&key)
194 }
195 }
196
197 #[cfg(feature = $feature)]
198 impl From<&$krate::ecdsa::VerifyingKey> for EcdsaPublicKey {
199 fn from(key: &$krate::ecdsa::VerifyingKey) -> EcdsaPublicKey {
200 EcdsaPublicKey::$curve(key.to_sec1_point(false))
201 }
202 }
203 };
204}
205
206impl_ecdsa_for_curve!(p256, "p256", NistP256);
207impl_ecdsa_for_curve!(p384, "p384", NistP384);
208impl_ecdsa_for_curve!(p521, "p521", NistP521);