1use thiserror::Error as ThisError;
2
3use crate::Curve;
4pub trait TypedCurve: Curve {
5 const CURVE_TYPE: CurveType;
6
7 #[inline]
8 fn to_base58(bytes: impl AsRef<[u8]>) -> String {
9 format!(
10 "{}:{}",
11 Self::CURVE_TYPE,
12 bs58::encode(bytes.as_ref()).into_string()
13 )
14 }
15
16 fn parse_base58<const N: usize>(s: impl AsRef<str>) -> Result<[u8; N], crate::ParseCurveError> {
17 let s = s.as_ref();
18 let data = if let Some((curve, data)) = s.split_once(':') {
19 if !curve.eq_ignore_ascii_case(Self::CURVE_TYPE.into()) {
20 return Err(crate::ParseCurveError::WrongCurveType);
21 }
22 data
23 } else {
24 s
25 };
26 checked_base58_decode_array(data)
27 }
28}
29
30#[derive(strum::Display, strum::IntoStaticStr, strum::EnumString)]
31#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
32#[repr(u8)]
33pub enum CurveType {
34 #[cfg(feature = "ed25519")]
35 Ed25519 = 0,
36 #[cfg(feature = "secp256k1")]
37 Secp256k1 = 1,
38 #[cfg(feature = "p256")]
39 P256 = 2,
40}
41
42#[derive(Debug, ThisError, PartialEq, Eq)]
43pub enum ParseCurveError {
44 #[error("wrong curve type")]
45 WrongCurveType,
46 #[error("base58: {0}")]
47 Base58(#[from] bs58::decode::Error),
48 #[error("invalid length")]
49 InvalidLength,
50}
51
52fn checked_base58_decode_array<const N: usize>(
53 input: impl AsRef<[u8]>,
54) -> Result<[u8; N], crate::ParseCurveError> {
55 let mut output = [0u8; N];
56 let n = bs58::decode(input.as_ref())
57 .onto(&mut output)?;
60 (n == N)
61 .then_some(output)
62 .ok_or(crate::ParseCurveError::InvalidLength)
63}