1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
5#![allow(non_snake_case)]
6#![forbid(unsafe_code)]
7#![warn(
8 clippy::unwrap_used,
9 missing_docs,
10 rust_2018_idioms,
11 unused_lifetimes,
12 unused_qualifications,
13 unreachable_pub
14)]
15
16mod hex;
74
75#[cfg(feature = "pkcs8")]
76pub mod pkcs8;
77
78#[cfg(feature = "serde")]
79mod serde;
80
81pub use signature::{self, Error, SignatureEncoding};
82
83use core::fmt;
84
85#[cfg(feature = "pkcs8")]
86pub use crate::pkcs8::{
87 KeypairBytes, PublicKeyBytes,
88 spki::{
89 AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
90 der::{AnyRef, oid::ObjectIdentifier},
91 },
92};
93
94#[cfg(all(feature = "alloc", feature = "pkcs8"))]
95use pkcs8::spki::{
96 SignatureBitStringEncoding,
97 der::{self, asn1::BitString},
98};
99
100pub const COMPONENT_SIZE: usize = 57;
102
103pub type ComponentBytes = [u8; COMPONENT_SIZE];
106
107pub type SignatureBytes = [u8; Signature::BYTE_SIZE];
109
110#[derive(Copy, Clone, Eq, Hash, PartialEq)]
119#[repr(C)]
120pub struct Signature {
121 R: ComponentBytes,
122 s: ComponentBytes,
123}
124
125impl Signature {
126 pub const BYTE_SIZE: usize = COMPONENT_SIZE * 2;
128
129 #[must_use]
131 pub fn from_bytes(bytes: &SignatureBytes) -> Self {
132 let mut R = [0; COMPONENT_SIZE];
133 let mut s = [0; COMPONENT_SIZE];
134
135 let components = bytes.split_at(COMPONENT_SIZE);
136 R.copy_from_slice(components.0);
137 s.copy_from_slice(components.1);
138
139 Self { R, s }
140 }
141
142 pub fn from_slice(bytes: &[u8]) -> signature::Result<Self> {
147 SignatureBytes::try_from(bytes)
148 .map(Into::into)
149 .map_err(|_| Error::new())
150 }
151
152 #[must_use]
154 pub fn r_bytes(&self) -> &ComponentBytes {
155 &self.R
156 }
157
158 #[must_use]
160 pub fn s_bytes(&self) -> &ComponentBytes {
161 &self.s
162 }
163
164 #[must_use]
166 pub fn to_bytes(&self) -> SignatureBytes {
167 let mut ret = [0u8; Self::BYTE_SIZE];
168 let (R, s) = ret.split_at_mut(COMPONENT_SIZE);
169 R.copy_from_slice(&self.R);
170 s.copy_from_slice(&self.s);
171 ret
172 }
173
174 pub fn from_components(r: impl Into<ComponentBytes>, s: impl Into<ComponentBytes>) -> Self {
177 Self {
178 R: r.into(),
179 s: s.into(),
180 }
181 }
182}
183
184impl SignatureEncoding for Signature {
185 type Repr = SignatureBytes;
186
187 fn to_bytes(&self) -> SignatureBytes {
188 self.to_bytes()
189 }
190}
191
192impl From<Signature> for SignatureBytes {
193 fn from(sig: Signature) -> SignatureBytes {
194 sig.to_bytes()
195 }
196}
197
198impl From<&Signature> for SignatureBytes {
199 fn from(sig: &Signature) -> SignatureBytes {
200 sig.to_bytes()
201 }
202}
203
204impl From<SignatureBytes> for Signature {
205 fn from(bytes: SignatureBytes) -> Self {
206 Signature::from_bytes(&bytes)
207 }
208}
209
210impl From<&SignatureBytes> for Signature {
211 fn from(bytes: &SignatureBytes) -> Self {
212 Signature::from_bytes(bytes)
213 }
214}
215
216impl TryFrom<&[u8]> for Signature {
217 type Error = Error;
218
219 fn try_from(bytes: &[u8]) -> signature::Result<Self> {
220 Self::from_slice(bytes)
221 }
222}
223
224impl fmt::Debug for Signature {
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 f.debug_struct("ed448::Signature")
227 .field("R", self.r_bytes())
228 .field("s", self.s_bytes())
229 .finish()
230 }
231}
232
233impl fmt::Display for Signature {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 write!(f, "{self:X}")
236 }
237}
238
239#[cfg(all(feature = "alloc", feature = "pkcs8"))]
240impl SignatureBitStringEncoding for Signature {
241 fn to_bitstring(&self) -> der::Result<BitString> {
242 BitString::new(0, self.to_bytes())
243 }
244}
245
246#[cfg(feature = "pkcs8")]
247impl AssociatedAlgorithmIdentifier for Signature {
248 type Params = AnyRef<'static>;
249
250 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs8::ALGORITHM_ID;
251}