1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
6 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
7)]
8#![forbid(unsafe_code)]
9#![warn(
10 clippy::cast_lossless,
11 clippy::cast_possible_truncation,
12 clippy::cast_possible_wrap,
13 clippy::cast_precision_loss,
14 clippy::cast_sign_loss,
15 clippy::checked_conversions,
16 clippy::implicit_saturating_sub,
17 clippy::panic,
18 clippy::panic_in_result_fn,
19 clippy::unwrap_used,
20 missing_docs,
21 rust_2018_idioms,
22 unused_lifetimes,
23 unused_qualifications
24)]
25
26#[cfg(feature = "alloc")]
58extern crate alloc;
59
60mod recovery;
61
62#[cfg(feature = "der")]
63#[cfg_attr(docsrs, doc(cfg(feature = "der")))]
64pub mod der;
65
66#[cfg(feature = "dev")]
67#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
68pub mod dev;
69
70#[cfg(feature = "hazmat")]
71#[cfg_attr(docsrs, doc(cfg(feature = "hazmat")))]
72pub mod hazmat;
73
74#[cfg(feature = "sign")]
75mod sign;
76
77#[cfg(feature = "verify")]
78mod verify;
79
80pub use crate::recovery::RecoveryId;
81
82pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve};
84
85pub use signature::{self, Error, Result};
87
88#[cfg(feature = "sign")]
89#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
90pub use crate::sign::SigningKey;
91
92#[cfg(feature = "verify")]
93#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
94pub use crate::verify::VerifyingKey;
95
96use core::{
97 fmt::{self, Debug},
98 ops::Add,
99};
100use elliptic_curve::{
101 bigint::Encoding as _,
102 generic_array::{sequence::Concat, ArrayLength, GenericArray},
103 FieldBytes, FieldSize, ScalarCore,
104};
105
106#[cfg(feature = "alloc")]
107use alloc::vec::Vec;
108
109#[cfg(feature = "arithmetic")]
110use {
111 core::str,
112 elliptic_curve::{ff::PrimeField, IsHigh, NonZeroScalar, ScalarArithmetic},
113};
114
115#[cfg(feature = "serde")]
116use serdect::serde::{de, ser, Deserialize, Serialize};
117
118pub type SignatureSize<C> = <FieldSize<C> as Add>::Output;
120
121pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
123
124#[derive(Clone, Eq, PartialEq)]
147pub struct Signature<C: PrimeCurve>
148where
149 SignatureSize<C>: ArrayLength<u8>,
150{
151 bytes: SignatureBytes<C>,
152}
153
154impl<C> Signature<C>
155where
156 C: PrimeCurve,
157 SignatureSize<C>: ArrayLength<u8>,
158{
159 #[cfg(feature = "der")]
161 #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
162 pub fn from_der(bytes: &[u8]) -> Result<Self>
163 where
164 der::MaxSize<C>: ArrayLength<u8>,
165 <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
166 {
167 der::Signature::<C>::try_from(bytes).and_then(Self::try_from)
168 }
169
170 pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> {
173 Self::try_from(r.into().concat(s.into()).as_slice())
174 }
175
176 pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) {
178 let (r_bytes, s_bytes) = self.bytes.split_at(C::UInt::BYTE_SIZE);
179
180 (
181 GenericArray::clone_from_slice(r_bytes),
182 GenericArray::clone_from_slice(s_bytes),
183 )
184 }
185
186 #[cfg(feature = "der")]
188 #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
189 pub fn to_der(&self) -> der::Signature<C>
190 where
191 der::MaxSize<C>: ArrayLength<u8>,
192 <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
193 {
194 let (r, s) = self.bytes.split_at(C::UInt::BYTE_SIZE);
195 der::Signature::from_scalar_bytes(r, s).expect("DER encoding error")
196 }
197
198 #[cfg(feature = "alloc")]
200 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
201 pub fn to_vec(&self) -> Vec<u8> {
202 self.bytes.to_vec()
203 }
204}
205
206#[cfg(feature = "arithmetic")]
207#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
208impl<C> Signature<C>
209where
210 C: PrimeCurve + ScalarArithmetic,
211 SignatureSize<C>: ArrayLength<u8>,
212{
213 pub fn r(&self) -> NonZeroScalar<C> {
215 NonZeroScalar::try_from(self.split_bytes().0.as_slice())
216 .expect("r-component ensured valid in constructor")
217 }
218
219 pub fn s(&self) -> NonZeroScalar<C> {
221 NonZeroScalar::try_from(self.split_bytes().1.as_slice())
222 .expect("s-component ensured valid in constructor")
223 }
224
225 pub fn split_scalars(&self) -> (NonZeroScalar<C>, NonZeroScalar<C>) {
227 (self.r(), self.s())
228 }
229
230 pub fn normalize_s(&self) -> Option<Self> {
235 let s = self.s();
236
237 if s.is_high().into() {
238 let neg_s = -s;
239 let mut result = self.clone();
240 result.bytes[C::UInt::BYTE_SIZE..].copy_from_slice(&neg_s.to_repr());
241 Some(result)
242 } else {
243 None
244 }
245 }
246}
247
248impl<C> signature::Signature for Signature<C>
249where
250 C: PrimeCurve,
251 SignatureSize<C>: ArrayLength<u8>,
252{
253 fn from_bytes(bytes: &[u8]) -> Result<Self> {
254 Self::try_from(bytes)
255 }
256}
257
258impl<C> AsRef<[u8]> for Signature<C>
259where
260 C: PrimeCurve,
261 SignatureSize<C>: ArrayLength<u8>,
262{
263 fn as_ref(&self) -> &[u8] {
264 self.bytes.as_slice()
265 }
266}
267
268impl<C> Copy for Signature<C>
269where
270 C: PrimeCurve,
271 SignatureSize<C>: ArrayLength<u8>,
272 <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
273{
274}
275
276impl<C> Debug for Signature<C>
277where
278 C: PrimeCurve,
279 SignatureSize<C>: ArrayLength<u8>,
280{
281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282 write!(f, "ecdsa::Signature<{:?}>(", C::default())?;
283
284 for &byte in self.as_ref() {
285 write!(f, "{:02X}", byte)?;
286 }
287
288 write!(f, ")")
289 }
290}
291
292impl<C> TryFrom<&[u8]> for Signature<C>
293where
294 C: PrimeCurve,
295 SignatureSize<C>: ArrayLength<u8>,
296{
297 type Error = Error;
298
299 fn try_from(bytes: &[u8]) -> Result<Self> {
300 if bytes.len() != C::UInt::BYTE_SIZE * 2 {
301 return Err(Error::new());
302 }
303
304 for scalar_bytes in bytes.chunks_exact(C::UInt::BYTE_SIZE) {
305 let scalar = ScalarCore::<C>::from_be_slice(scalar_bytes).map_err(|_| Error::new())?;
306
307 if scalar.is_zero().into() {
308 return Err(Error::new());
309 }
310 }
311
312 Ok(Self {
313 bytes: GenericArray::clone_from_slice(bytes),
314 })
315 }
316}
317
318impl<C> fmt::Display for Signature<C>
319where
320 C: PrimeCurve,
321 SignatureSize<C>: ArrayLength<u8>,
322{
323 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324 write!(f, "{:X}", self)
325 }
326}
327
328impl<C> fmt::LowerHex for Signature<C>
329where
330 C: PrimeCurve,
331 SignatureSize<C>: ArrayLength<u8>,
332{
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 for byte in &self.bytes {
335 write!(f, "{:02x}", byte)?;
336 }
337 Ok(())
338 }
339}
340
341impl<C> fmt::UpperHex for Signature<C>
342where
343 C: PrimeCurve,
344 SignatureSize<C>: ArrayLength<u8>,
345{
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 for byte in &self.bytes {
348 write!(f, "{:02X}", byte)?;
349 }
350 Ok(())
351 }
352}
353
354#[cfg(feature = "arithmetic")]
355#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
356impl<C> str::FromStr for Signature<C>
357where
358 C: PrimeCurve + ScalarArithmetic,
359 SignatureSize<C>: ArrayLength<u8>,
360{
361 type Err = Error;
362
363 fn from_str(hex: &str) -> Result<Self> {
364 if hex.as_bytes().len() != C::UInt::BYTE_SIZE * 4 {
365 return Err(Error::new());
366 }
367
368 if !hex
370 .as_bytes()
371 .iter()
372 .all(|&byte| matches!(byte, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z'))
373 {
374 return Err(Error::new());
375 }
376
377 let (r_hex, s_hex) = hex.split_at(C::UInt::BYTE_SIZE * 2);
378
379 let r = r_hex
380 .parse::<NonZeroScalar<C>>()
381 .map_err(|_| Error::new())?;
382
383 let s = s_hex
384 .parse::<NonZeroScalar<C>>()
385 .map_err(|_| Error::new())?;
386
387 Self::from_scalars(r, s)
388 }
389}
390
391#[cfg(feature = "serde")]
392#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
393impl<C> Serialize for Signature<C>
394where
395 C: PrimeCurve,
396 SignatureSize<C>: ArrayLength<u8>,
397{
398 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
399 where
400 S: ser::Serializer,
401 {
402 serdect::array::serialize_hex_upper_or_bin(&self.bytes, serializer)
403 }
404}
405
406#[cfg(feature = "serde")]
407#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
408impl<'de, C> Deserialize<'de> for Signature<C>
409where
410 C: PrimeCurve,
411 SignatureSize<C>: ArrayLength<u8>,
412{
413 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
414 where
415 D: de::Deserializer<'de>,
416 {
417 let mut bytes = SignatureBytes::<C>::default();
418 serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?;
419 Self::try_from(bytes.as_slice()).map_err(de::Error::custom)
420 }
421}