#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[macro_use]
extern crate amplify;
mod digest;
#[cfg(feature = "x25519")]
pub mod x25519;
#[cfg(feature = "ed25519")]
pub mod ed25519;
pub mod display;
use std::fmt::Debug;
pub use digest::*;
use crate::display::{Encoding, MultiDisplay};
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From, Default)]
#[display("invalid secret key")]
#[non_exhaustive]
pub struct EcSkInvalid {}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From, Default)]
#[display("invalid public key")]
#[non_exhaustive]
pub struct EcPkInvalid {}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From, Default)]
#[display("invalid signature data")]
#[non_exhaustive]
pub struct EcSigInvalid {}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)]
#[display(doc_comments)]
#[non_exhaustive]
pub enum EcdhError {
WeakPk,
#[display(inner)]
#[from]
InvalidPk(EcPkInvalid),
#[display(inner)]
#[from]
InvalidSk(EcSkInvalid),
}
#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum EcSerError {
#[display(inner)]
#[from]
Io(amplify::IoError),
InvalidKeyLength(usize),
#[display(inner)]
#[from]
InvalidKey(EcPkInvalid),
DataEncoding(String),
}
#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum EcVerifyError {
WeakPk,
#[display(inner)]
#[from]
InvalidPk(EcPkInvalid),
#[display(inner)]
#[from]
InvalidSignature(EcSigInvalid),
SignatureMismatch,
}
pub trait EcPk: Clone + Eq + Send + Debug + MultiDisplay<Encoding> {
const COMPRESSED_LEN: usize;
const CURVE_NAME: &'static str;
type Compressed: Copy + Sized + Send + AsRef<[u8]>;
fn base_point() -> Self;
fn to_pk_compressed(&self) -> Self::Compressed;
fn from_pk_compressed(pk: Self::Compressed) -> Result<Self, EcPkInvalid>;
fn from_pk_compressed_slice(slice: &[u8]) -> Result<Self, EcPkInvalid>;
}
pub trait EcSk: Clone + Eq + Send {
type Pk: EcPk;
fn generate_keypair() -> (Self, Self::Pk)
where Self: Sized;
fn to_pk(&self) -> Result<Self::Pk, EcSkInvalid>;
}
pub trait EcSig: Clone + Eq + Sized + Send + AsRef<[u8]> + Debug + MultiDisplay<Encoding> {
const COMPRESSED_LEN: usize;
type Pk: EcPk;
type Compressed: Copy + Sized + Send + AsRef<[u8]>;
fn to_sig_compressed(&self) -> Self::Compressed;
fn from_sig_compressed(sig: Self::Compressed) -> Result<Self, EcSigInvalid>;
fn from_sig_compressed_slice(slice: &[u8]) -> Result<Self, EcSigInvalid>;
fn verify(&self, pk: &Self::Pk, msg: impl AsRef<[u8]>) -> Result<(), EcVerifyError>;
}
pub trait Ecdh: EcSk {
type SharedSecret: Copy + Eq + Sized + Send + AsRef<[u8]>;
fn ecdh(&self, pk: &Self::Pk) -> Result<Self::SharedSecret, EcdhError>;
}
pub trait EcSign: EcSk {
type Sig: EcSig<Pk = Self::Pk>;
fn cert(&self) -> Result<Cert<Self::Sig>, EcSkInvalid> {
let pk = self.to_pk()?;
let sig = self.sign(pk.to_pk_compressed());
Ok(Cert { pk, sig })
}
fn sign(&self, msg: impl AsRef<[u8]>) -> Self::Sig;
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct CertFormat {
pub enc: Encoding,
pub sep: &'static str,
}
impl CertFormat {
pub fn new(sep: &'static str, enc: Encoding) -> Self { CertFormat { enc, sep } }
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Cert<S: EcSig> {
pub pk: S::Pk,
pub sig: S,
}
impl<S: EcSig> MultiDisplay<CertFormat> for Cert<S>
where
S: MultiDisplay<Encoding>,
S::Pk: MultiDisplay<Encoding>,
{
type Display = String;
fn display_fmt(&self, f: &CertFormat) -> Self::Display {
format!("{}{}{}", self.pk.display_fmt(&f.enc), f.sep, self.sig.display_fmt(&f.enc))
}
}
impl<S: EcSig> Cert<S> {
pub fn verify(&self) -> Result<(), EcVerifyError> {
self.sig.verify(&self.pk, self.pk.to_pk_compressed())
}
}
#[cfg(feature = "ec25519")]
mod ec22519_err_convert {
use ec25519::Error;
use super::*;
impl From<Error> for EcPkInvalid {
fn from(err: Error) -> Self {
match err {
Error::InvalidPublicKey => EcPkInvalid {},
Error::WeakPublicKey
| Error::InvalidSecretKey
| Error::SignatureMismatch
| Error::InvalidSignature
| Error::InvalidSeed
| Error::InvalidBlind
| Error::InvalidNoise
| Error::ParseError
| Error::NonCanonical => {
unreachable!("ECDH in ed25519-compact crate should not generate this errors")
}
}
}
}
impl From<Error> for EcSkInvalid {
fn from(err: Error) -> Self {
match err {
Error::InvalidSecretKey => EcSkInvalid {},
Error::WeakPublicKey
| Error::InvalidPublicKey
| Error::SignatureMismatch
| Error::InvalidSignature
| Error::InvalidSeed
| Error::InvalidBlind
| Error::InvalidNoise
| Error::ParseError
| Error::NonCanonical => {
unreachable!("ECDH in ed25519-compact crate should not generate this errors")
}
}
}
}
impl From<Error> for EcSerError {
fn from(err: Error) -> Self { EcSerError::DataEncoding(err.to_string()) }
}
impl From<Error> for EcdhError {
fn from(err: Error) -> Self {
match err {
Error::WeakPublicKey => EcdhError::WeakPk,
Error::InvalidPublicKey => EcdhError::InvalidPk(EcPkInvalid {}),
Error::InvalidSecretKey => EcdhError::InvalidSk(EcSkInvalid {}),
Error::SignatureMismatch
| Error::InvalidSignature
| Error::InvalidSeed
| Error::InvalidBlind
| Error::InvalidNoise
| Error::ParseError
| Error::NonCanonical => {
unreachable!("ECDH in ed25519-compact crate should not generate this errors")
}
}
}
}
impl From<Error> for EcVerifyError {
fn from(err: Error) -> Self {
match err {
Error::WeakPublicKey => EcVerifyError::WeakPk,
Error::InvalidPublicKey => EcVerifyError::InvalidPk(EcPkInvalid {}),
Error::SignatureMismatch => EcVerifyError::SignatureMismatch,
Error::InvalidSignature => EcVerifyError::InvalidSignature(EcSigInvalid {}),
Error::InvalidSecretKey
| Error::InvalidSeed
| Error::InvalidBlind
| Error::InvalidNoise
| Error::ParseError
| Error::NonCanonical => {
unreachable!("ECDH in ed25519-compact crate should not generate this errors")
}
}
}
}
}
#[cfg(feature = "multibase")]
impl From<multibase::Error> for EcSerError {
fn from(err: multibase::Error) -> Self { EcSerError::DataEncoding(err.to_string()) }
}