#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
#![allow(non_snake_case)]
#![forbid(unsafe_code)]
#![warn(
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications,
unreachable_pub
)]
mod hex;
#[cfg(feature = "pkcs8")]
pub mod pkcs8;
#[cfg(feature = "serde")]
mod serde;
pub use signature::{self, Error, SignatureEncoding};
use core::fmt;
#[cfg(feature = "pkcs8")]
pub use crate::pkcs8::{
KeypairBytes, PublicKeyBytes,
spki::{
AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
der::{AnyRef, oid::ObjectIdentifier},
},
};
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
use pkcs8::spki::{
SignatureBitStringEncoding,
der::{self, asn1::BitString},
};
pub const COMPONENT_SIZE: usize = 57;
pub type ComponentBytes = [u8; COMPONENT_SIZE];
pub type SignatureBytes = [u8; Signature::BYTE_SIZE];
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
#[repr(C)]
pub struct Signature {
R: ComponentBytes,
s: ComponentBytes,
}
impl Signature {
pub const BYTE_SIZE: usize = COMPONENT_SIZE * 2;
#[must_use]
pub fn from_bytes(bytes: &SignatureBytes) -> Self {
let mut R = [0; COMPONENT_SIZE];
let mut s = [0; COMPONENT_SIZE];
let components = bytes.split_at(COMPONENT_SIZE);
R.copy_from_slice(components.0);
s.copy_from_slice(components.1);
Self { R, s }
}
pub fn from_slice(bytes: &[u8]) -> signature::Result<Self> {
SignatureBytes::try_from(bytes)
.map(Into::into)
.map_err(|_| Error::new())
}
#[must_use]
pub fn r_bytes(&self) -> &ComponentBytes {
&self.R
}
#[must_use]
pub fn s_bytes(&self) -> &ComponentBytes {
&self.s
}
#[must_use]
pub fn to_bytes(&self) -> SignatureBytes {
let mut ret = [0u8; Self::BYTE_SIZE];
let (R, s) = ret.split_at_mut(COMPONENT_SIZE);
R.copy_from_slice(&self.R);
s.copy_from_slice(&self.s);
ret
}
pub fn from_components(r: impl Into<ComponentBytes>, s: impl Into<ComponentBytes>) -> Self {
Self {
R: r.into(),
s: s.into(),
}
}
}
impl SignatureEncoding for Signature {
type Repr = SignatureBytes;
fn to_bytes(&self) -> SignatureBytes {
self.to_bytes()
}
}
impl From<Signature> for SignatureBytes {
fn from(sig: Signature) -> SignatureBytes {
sig.to_bytes()
}
}
impl From<&Signature> for SignatureBytes {
fn from(sig: &Signature) -> SignatureBytes {
sig.to_bytes()
}
}
impl From<SignatureBytes> for Signature {
fn from(bytes: SignatureBytes) -> Self {
Signature::from_bytes(&bytes)
}
}
impl From<&SignatureBytes> for Signature {
fn from(bytes: &SignatureBytes) -> Self {
Signature::from_bytes(bytes)
}
}
impl TryFrom<&[u8]> for Signature {
type Error = Error;
fn try_from(bytes: &[u8]) -> signature::Result<Self> {
Self::from_slice(bytes)
}
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ed448::Signature")
.field("R", self.r_bytes())
.field("s", self.s_bytes())
.finish()
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:X}")
}
}
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
impl SignatureBitStringEncoding for Signature {
fn to_bitstring(&self) -> der::Result<BitString> {
BitString::new(0, self.to_bytes())
}
}
#[cfg(feature = "pkcs8")]
impl AssociatedAlgorithmIdentifier for Signature {
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs8::ALGORITHM_ID;
}