1#![no_std]
46#![cfg_attr(docsrs, feature(doc_cfg))]
47#![forbid(unsafe_code, clippy::unwrap_used)]
48#![warn(missing_docs, rust_2018_idioms)]
49#![doc(
50 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
51 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
52 html_root_url = "https://docs.rs/ecdsa/0.13.0-pre"
53)]
54
55#[cfg(feature = "alloc")]
56extern crate alloc;
57
58#[cfg(feature = "der")]
59#[cfg_attr(docsrs, doc(cfg(feature = "der")))]
60pub mod der;
61
62#[cfg(feature = "dev")]
63#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
64pub mod dev;
65
66#[cfg(feature = "hazmat")]
67#[cfg_attr(docsrs, doc(cfg(feature = "hazmat")))]
68pub mod hazmat;
69
70#[cfg(feature = "sign")]
71#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
72pub mod rfc6979;
73
74#[cfg(feature = "sign")]
75mod sign;
76
77#[cfg(feature = "verify")]
78mod verify;
79
80pub use elliptic_curve_flow::{self, sec1::EncodedPoint, PrimeCurve};
82
83pub use signature_flow::{self, Error, Result};
85
86#[cfg(feature = "sign")]
87#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
88pub use sign::SigningKey;
89
90#[cfg(feature = "verify")]
91#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
92pub use verify::VerifyingKey;
93
94use core::{
95 convert::TryFrom,
96 fmt::{self, Debug},
97 ops::Add,
98};
99use elliptic_curve_flow::{
100 bigint::Encoding as _,
101 generic_array::{sequence::Concat, ArrayLength, GenericArray},
102 FieldBytes, FieldSize, ScalarCore,
103};
104
105#[cfg(feature = "arithmetic")]
106use elliptic_curve_flow::{group::ff::PrimeField, NonZeroScalar, ProjectiveArithmetic, Scalar};
107
108pub type SignatureSize<C> = <FieldSize<C> as Add>::Output;
110
111pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
113
114#[derive(Clone, Eq, PartialEq)]
128pub struct Signature<C: PrimeCurve>
129where
130 SignatureSize<C>: ArrayLength<u8>,
131{
132 bytes: SignatureBytes<C>,
133}
134
135impl<C> Signature<C>
136where
137 C: PrimeCurve,
138 SignatureSize<C>: ArrayLength<u8>,
139{
140 #[cfg(feature = "der")]
142 #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
143 pub fn from_der(bytes: &[u8]) -> Result<Self>
144 where
145 der::MaxSize<C>: ArrayLength<u8>,
146 <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
147 {
148 der::Signature::<C>::try_from(bytes).and_then(Self::try_from)
149 }
150
151 pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> {
154 Self::try_from(r.into().concat(s.into()).as_slice())
155 }
156
157 pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) {
159 let (r_bytes, s_bytes) = self.bytes.split_at(C::UInt::BYTE_SIZE);
160
161 (
162 GenericArray::clone_from_slice(r_bytes),
163 GenericArray::clone_from_slice(s_bytes),
164 )
165 }
166
167 #[cfg(feature = "der")]
169 #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
170 pub fn to_der(&self) -> der::Signature<C>
171 where
172 der::MaxSize<C>: ArrayLength<u8>,
173 <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
174 {
175 let (r, s) = self.bytes.split_at(C::UInt::BYTE_SIZE);
176 der::Signature::from_scalar_bytes(r, s).expect("DER encoding error")
177 }
178}
179
180#[cfg(feature = "arithmetic")]
181#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
182impl<C> Signature<C>
183where
184 C: PrimeCurve + ProjectiveArithmetic,
185 SignatureSize<C>: ArrayLength<u8>,
186{
187 pub fn r(&self) -> NonZeroScalar<C> {
189 NonZeroScalar::try_from(self.split_bytes().0.as_slice())
190 .expect("r-component ensured valid in constructor")
191 }
192
193 pub fn s(&self) -> NonZeroScalar<C> {
195 NonZeroScalar::try_from(self.split_bytes().1.as_slice())
196 .expect("s-component ensured valid in constructor")
197 }
198
199 pub fn split_scalars(&self) -> (NonZeroScalar<C>, NonZeroScalar<C>) {
201 (self.r(), self.s())
202 }
203
204 pub fn normalize_s(&self) -> Option<Self>
209 where
210 Scalar<C>: NormalizeLow,
211 {
212 self.s().normalize_low().map(|s_low| {
213 let mut result = self.clone();
214 result.bytes[C::UInt::BYTE_SIZE..].copy_from_slice(&s_low.to_repr());
215 result
216 })
217 }
218}
219
220impl<C> signature_flow::Signature for Signature<C>
221where
222 C: PrimeCurve,
223 SignatureSize<C>: ArrayLength<u8>,
224{
225 fn from_bytes(bytes: &[u8]) -> Result<Self> {
226 Self::try_from(bytes)
227 }
228}
229
230impl<C> AsRef<[u8]> for Signature<C>
231where
232 C: PrimeCurve,
233 SignatureSize<C>: ArrayLength<u8>,
234{
235 fn as_ref(&self) -> &[u8] {
236 self.bytes.as_slice()
237 }
238}
239
240impl<C> Copy for Signature<C>
241where
242 C: PrimeCurve,
243 SignatureSize<C>: ArrayLength<u8>,
244 <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
245{
246}
247
248impl<C> Debug for Signature<C>
249where
250 C: PrimeCurve,
251 SignatureSize<C>: ArrayLength<u8>,
252{
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 write!(
255 f,
256 "ecdsa::Signature<{:?}>({:?})",
257 C::default(),
258 self.as_ref()
259 )
260 }
261}
262
263impl<C> TryFrom<&[u8]> for Signature<C>
264where
265 C: PrimeCurve,
266 SignatureSize<C>: ArrayLength<u8>,
267{
268 type Error = Error;
269
270 fn try_from(bytes: &[u8]) -> Result<Self> {
271 if bytes.len() != C::UInt::BYTE_SIZE * 2 {
272 return Err(Error::new());
273 }
274
275 for scalar_bytes in bytes.chunks_exact(C::UInt::BYTE_SIZE) {
276 let scalar = ScalarCore::<C>::from_be_slice(scalar_bytes).map_err(|_| Error::new())?;
277
278 if scalar.is_zero().into() {
279 return Err(Error::new());
280 }
281 }
282
283 Ok(Self {
284 bytes: GenericArray::clone_from_slice(bytes),
285 })
286 }
287}
288
289pub trait NormalizeLow: Sized {
294 fn normalize_low(&self) -> Option<Self>;
302}