1#![no_std]
2#![forbid(unsafe_code)]
3#![warn(missing_docs, rust_2018_idioms)]
4#![doc = include_str!("../README.md")]
5#![doc(
6 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
7 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
8)]
9
10#![cfg_attr(feature = "hazmat", doc = "```")]
16#![cfg_attr(not(feature = "hazmat"), doc = "```ignore")]
17#![cfg_attr(feature = "hazmat", doc = "```")]
27#![cfg_attr(not(feature = "hazmat"), doc = "```ignore")]
28extern crate alloc;
54
55#[cfg(feature = "hazmat")]
56pub use crate::signing_key::SigningKey;
57
58pub use crate::{components::Components, size::KeySize, verifying_key::VerifyingKey};
59
60pub use crypto_bigint::{BoxedUint, NonZero, Odd};
61pub use pkcs8;
62pub use signature;
63
64use pkcs8::spki::ObjectIdentifier;
65
66mod components;
67mod generate;
68mod signing_key;
69mod size;
70mod verifying_key;
71
72pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10040.4.1");
76
77use alloc::{boxed::Box, vec::Vec};
78use pkcs8::der::{
79 self, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence,
80 Writer, asn1::UintRef,
81};
82use signature::SignatureEncoding;
83
84#[derive(Clone, Debug)]
86#[must_use]
87pub struct Signature {
88 r: NonZero<BoxedUint>,
90
91 s: NonZero<BoxedUint>,
93}
94
95impl Signature {
96 pub fn from_components(r: NonZero<BoxedUint>, s: NonZero<BoxedUint>) -> Self {
98 Self { r, s }
99 }
100
101 #[must_use]
103 pub fn r(&self) -> &NonZero<BoxedUint> {
104 &self.r
105 }
106
107 #[must_use]
109 pub fn s(&self) -> &NonZero<BoxedUint> {
110 &self.s
111 }
112}
113
114impl<'a> DecodeValue<'a> for Signature {
115 type Error = der::Error;
116
117 fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
118 reader.read_nested(header.length, |reader| {
119 let r = UintRef::decode(reader)?;
120 let s = UintRef::decode(reader)?;
121
122 let r = BoxedUint::from_be_slice(r.as_bytes(), r.as_bytes().len() as u32 * 8)
123 .map_err(|_| UintRef::TAG.value_error())?;
124 let s = BoxedUint::from_be_slice(s.as_bytes(), s.as_bytes().len() as u32 * 8)
125 .map_err(|_| UintRef::TAG.value_error())?;
126
127 let r = NonZero::new(r)
128 .into_option()
129 .ok_or(UintRef::TAG.value_error())?;
130 let s = NonZero::new(s)
131 .into_option()
132 .ok_or(UintRef::TAG.value_error())?;
133
134 Ok(Self::from_components(r, s))
135 })
136 }
137}
138
139impl EncodeValue for Signature {
140 fn value_len(&self) -> der::Result<Length> {
141 UintRef::new(&self.r.to_be_bytes())?.encoded_len()?
142 + UintRef::new(&self.s.to_be_bytes())?.encoded_len()?
143 }
144
145 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
146 UintRef::new(&self.r.to_be_bytes())?.encode(writer)?;
147 UintRef::new(&self.s.to_be_bytes())?.encode(writer)?;
148 Ok(())
149 }
150}
151
152impl From<Signature> for Box<[u8]> {
153 fn from(sig: Signature) -> Box<[u8]> {
154 sig.to_bytes()
155 }
156}
157
158impl PartialEq for Signature {
159 fn eq(&self, other: &Self) -> bool {
160 self.r().eq(other.r()) && self.s().eq(other.s())
161 }
162}
163
164impl PartialOrd for Signature {
165 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
166 (self.r(), self.s()).partial_cmp(&(other.r(), other.s()))
167 }
168}
169
170impl Sequence<'_> for Signature {}
171
172impl SignatureEncoding for Signature {
173 type Repr = Box<[u8]>;
174
175 fn to_bytes(&self) -> Box<[u8]> {
176 SignatureEncoding::to_vec(self).into_boxed_slice()
177 }
178
179 fn to_vec(&self) -> Vec<u8> {
180 self.to_der().expect("DER encoding error")
181 }
182}
183
184impl TryFrom<&[u8]> for Signature {
185 type Error = signature::Error;
186
187 fn try_from(bytes: &[u8]) -> signature::Result<Self> {
188 Self::from_der(bytes).map_err(|_| signature::Error::new())
190 }
191}
192
193#[inline]
195fn two() -> BoxedUint {
196 BoxedUint::from(2_u8)
197}