defuse_crypto/curve/
mod.rs

1mod ed25519;
2mod p256;
3mod secp256k1;
4
5pub use self::{ed25519::*, p256::*, secp256k1::*};
6
7use near_sdk::bs58;
8use strum::{Display, EnumString, IntoStaticStr};
9use thiserror::Error as ThisError;
10
11pub trait Curve {
12    type PublicKey;
13    type Signature;
14
15    /// Message that can be signed by this curve
16    type Message: AsRef<[u8]> + ?Sized;
17
18    /// Public key that should be known prior to verification
19    type VerifyingKey;
20
21    fn verify(
22        signature: &Self::Signature,
23        message: &Self::Message,
24        verifying_key: &Self::VerifyingKey,
25    ) -> Option<Self::PublicKey>;
26}
27
28#[derive(Display, IntoStaticStr, EnumString)]
29#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
30pub enum CurveType {
31    Ed25519,
32    Secp256k1,
33    P256,
34}
35
36pub trait TypedCurve: Curve {
37    const CURVE_TYPE: CurveType;
38
39    #[inline]
40    fn to_base58(bytes: impl AsRef<[u8]>) -> String {
41        format!(
42            "{}:{}",
43            Self::CURVE_TYPE,
44            bs58::encode(bytes.as_ref()).into_string()
45        )
46    }
47
48    fn parse_base58<const N: usize>(s: impl AsRef<str>) -> Result<[u8; N], ParseCurveError> {
49        let s = s.as_ref();
50        let data = if let Some((curve, data)) = s.split_once(':') {
51            if !curve.eq_ignore_ascii_case(Self::CURVE_TYPE.into()) {
52                return Err(ParseCurveError::WrongCurveType);
53            }
54            data
55        } else {
56            s
57        };
58        bs58::decode(data.as_bytes())
59            .into_array_const()
60            .map_err(Into::into)
61    }
62}
63
64#[derive(Debug, ThisError)]
65pub enum ParseCurveError {
66    #[error("wrong curve type")]
67    WrongCurveType,
68    #[error("base58: {0}")]
69    Base58(#[from] bs58::decode::Error),
70}