1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
23
24#[macro_use]
28extern crate amplify;
29
30mod digest;
31#[cfg(feature = "x25519")]
32pub mod x25519;
33#[cfg(feature = "ed25519")]
34pub mod ed25519;
35
36pub mod display;
37
38use std::fmt::Debug;
39
40pub use digest::*;
41
42use crate::display::{Encoding, MultiDisplay};
43
44#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From, Default)]
45#[display("invalid secret key")]
46#[non_exhaustive]
47pub struct EcSkInvalid {}
48
49#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From, Default)]
50#[display("invalid public key")]
51#[non_exhaustive]
52pub struct EcPkInvalid {}
53
54#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From, Default)]
55#[display("invalid signature data")]
56#[non_exhaustive]
57pub struct EcSigInvalid {}
58
59#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)]
60#[display(doc_comments)]
61#[non_exhaustive]
62pub enum EcdhError {
63 WeakPk,
65
66 #[display(inner)]
67 #[from]
68 InvalidPk(EcPkInvalid),
69
70 #[display(inner)]
71 #[from]
72 InvalidSk(EcSkInvalid),
73}
74
75#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
76#[display(doc_comments)]
77pub enum EcSerError {
78 #[display(inner)]
79 #[from]
80 Io(amplify::IoError),
81
82 InvalidKeyLength(usize),
84
85 #[display(inner)]
86 #[from]
87 InvalidKey(EcPkInvalid),
88
89 DataEncoding(String),
91}
92
93#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
94#[display(doc_comments)]
95pub enum EcVerifyError {
96 WeakPk,
98
99 #[display(inner)]
100 #[from]
101 InvalidPk(EcPkInvalid),
102
103 #[display(inner)]
104 #[from]
105 InvalidSignature(EcSigInvalid),
106
107 SignatureMismatch,
110}
111
112pub trait EcPk: Clone + Eq + Send + Debug + MultiDisplay<Encoding> {
118 const COMPRESSED_LEN: usize;
119 const CURVE_NAME: &'static str;
120
121 type Compressed: Copy + Sized + Send + AsRef<[u8]>;
123
124 fn base_point() -> Self;
125
126 fn to_pk_compressed(&self) -> Self::Compressed;
127 fn from_pk_compressed(pk: Self::Compressed) -> Result<Self, EcPkInvalid>;
128 fn from_pk_compressed_slice(slice: &[u8]) -> Result<Self, EcPkInvalid>;
129}
130
131pub trait EcSk: Clone + Eq + Send {
137 type Pk: EcPk;
138
139 fn generate_keypair() -> (Self, Self::Pk)
140 where Self: Sized;
141 fn to_pk(&self) -> Result<Self::Pk, EcSkInvalid>;
142}
143
144pub trait EcSig: Clone + Eq + Sized + Send + AsRef<[u8]> + Debug + MultiDisplay<Encoding> {
146 const COMPRESSED_LEN: usize;
147
148 type Pk: EcPk;
149 type Compressed: Copy + Sized + Send + AsRef<[u8]>;
151
152 fn to_sig_compressed(&self) -> Self::Compressed;
153 fn from_sig_compressed(sig: Self::Compressed) -> Result<Self, EcSigInvalid>;
154 fn from_sig_compressed_slice(slice: &[u8]) -> Result<Self, EcSigInvalid>;
155
156 fn verify(&self, pk: &Self::Pk, msg: impl AsRef<[u8]>) -> Result<(), EcVerifyError>;
157}
158
159pub trait Ecdh: EcSk {
165 type SharedSecret: Copy + Eq + Sized + Send + AsRef<[u8]>;
166
167 fn ecdh(&self, pk: &Self::Pk) -> Result<Self::SharedSecret, EcdhError>;
168}
169
170pub trait EcSign: EcSk {
172 type Sig: EcSig<Pk = Self::Pk>;
173
174 fn cert(&self) -> Result<Cert<Self::Sig>, EcSkInvalid> {
175 let pk = self.to_pk()?;
176 let sig = self.sign(pk.to_pk_compressed());
177 Ok(Cert { pk, sig })
178 }
179 fn sign(&self, msg: impl AsRef<[u8]>) -> Self::Sig;
180}
181
182#[derive(Clone, Eq, PartialEq, Debug)]
183pub struct CertFormat {
184 pub enc: Encoding,
185 pub sep: &'static str,
186}
187
188impl CertFormat {
189 pub fn new(sep: &'static str, enc: Encoding) -> Self { CertFormat { enc, sep } }
190}
191
192#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
193pub struct Cert<S: EcSig> {
194 pub pk: S::Pk,
195 pub sig: S,
196}
197
198impl<S: EcSig> MultiDisplay<CertFormat> for Cert<S>
199where
200 S: MultiDisplay<Encoding>,
201 S::Pk: MultiDisplay<Encoding>,
202{
203 type Display = String;
204 fn display_fmt(&self, f: &CertFormat) -> Self::Display {
205 format!("{}{}{}", self.pk.display_fmt(&f.enc), f.sep, self.sig.display_fmt(&f.enc))
206 }
207}
208
209impl<S: EcSig> Cert<S> {
210 pub fn verify(&self) -> Result<(), EcVerifyError> {
211 self.sig.verify(&self.pk, self.pk.to_pk_compressed())
212 }
213}
214
215#[cfg(feature = "ec25519")]
216mod ec22519_err_convert {
217 use ec25519::Error;
218
219 use super::*;
220
221 impl From<Error> for EcPkInvalid {
222 fn from(err: Error) -> Self {
223 match err {
224 Error::InvalidPublicKey => EcPkInvalid {},
225
226 Error::WeakPublicKey
227 | Error::InvalidSecretKey
228 | Error::SignatureMismatch
229 | Error::InvalidSignature
230 | Error::InvalidSeed
231 | Error::InvalidBlind
232 | Error::InvalidNoise
233 | Error::ParseError
234 | Error::NonCanonical => {
235 unreachable!("ECDH in ed25519-compact crate should not generate this errors")
236 }
237 }
238 }
239 }
240
241 impl From<Error> for EcSkInvalid {
242 fn from(err: Error) -> Self {
243 match err {
244 Error::InvalidSecretKey => EcSkInvalid {},
245
246 Error::WeakPublicKey
247 | Error::InvalidPublicKey
248 | Error::SignatureMismatch
249 | Error::InvalidSignature
250 | Error::InvalidSeed
251 | Error::InvalidBlind
252 | Error::InvalidNoise
253 | Error::ParseError
254 | Error::NonCanonical => {
255 unreachable!("ECDH in ed25519-compact crate should not generate this errors")
256 }
257 }
258 }
259 }
260
261 impl From<Error> for EcSerError {
262 fn from(err: Error) -> Self { EcSerError::DataEncoding(err.to_string()) }
263 }
264
265 impl From<Error> for EcdhError {
266 fn from(err: Error) -> Self {
267 match err {
268 Error::WeakPublicKey => EcdhError::WeakPk,
269 Error::InvalidPublicKey => EcdhError::InvalidPk(EcPkInvalid {}),
270 Error::InvalidSecretKey => EcdhError::InvalidSk(EcSkInvalid {}),
271
272 Error::SignatureMismatch
273 | Error::InvalidSignature
274 | Error::InvalidSeed
275 | Error::InvalidBlind
276 | Error::InvalidNoise
277 | Error::ParseError
278 | Error::NonCanonical => {
279 unreachable!("ECDH in ed25519-compact crate should not generate this errors")
280 }
281 }
282 }
283 }
284
285 impl From<Error> for EcVerifyError {
286 fn from(err: Error) -> Self {
287 match err {
288 Error::WeakPublicKey => EcVerifyError::WeakPk,
289 Error::InvalidPublicKey => EcVerifyError::InvalidPk(EcPkInvalid {}),
290 Error::SignatureMismatch => EcVerifyError::SignatureMismatch,
291 Error::InvalidSignature => EcVerifyError::InvalidSignature(EcSigInvalid {}),
292
293 Error::InvalidSecretKey
294 | Error::InvalidSeed
295 | Error::InvalidBlind
296 | Error::InvalidNoise
297 | Error::ParseError
298 | Error::NonCanonical => {
299 unreachable!("ECDH in ed25519-compact crate should not generate this errors")
300 }
301 }
302 }
303 }
304}
305
306#[cfg(feature = "multibase")]
307impl From<multibase::Error> for EcSerError {
308 fn from(err: multibase::Error) -> Self { EcSerError::DataEncoding(err.to_string()) }
309}