defuse_crypto/
signature.rs

1use core::{
2    fmt::{self, Debug, Display},
3    str::FromStr,
4};
5
6use near_sdk::{bs58, near};
7
8use crate::{Curve, CurveType, Ed25519, P256, ParseCurveError, Secp256k1};
9
10#[near(serializers = [borsh])]
11#[cfg_attr(
12    feature = "serde",
13    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
14)]
15#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
16pub enum Signature {
17    Ed25519(<Ed25519 as Curve>::Signature),
18    Secp256k1(<Secp256k1 as Curve>::Signature),
19    P256(<P256 as Curve>::Signature),
20}
21
22impl Signature {
23    #[inline]
24    pub const fn curve_type(&self) -> CurveType {
25        match self {
26            Self::Ed25519(_) => CurveType::Ed25519,
27            Self::Secp256k1(_) => CurveType::Secp256k1,
28            Self::P256(_) => CurveType::P256,
29        }
30    }
31
32    #[inline]
33    const fn data(&self) -> &[u8] {
34        #[allow(clippy::match_same_arms)]
35        match self {
36            Self::Ed25519(data) => data,
37            Self::Secp256k1(data) => data,
38            Self::P256(data) => data,
39        }
40    }
41}
42
43impl Debug for Signature {
44    #[inline]
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        write!(
47            f,
48            "{}:{}",
49            self.curve_type(),
50            bs58::encode(self.data()).into_string()
51        )
52    }
53}
54
55impl Display for Signature {
56    #[inline]
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        fmt::Debug::fmt(self, f)
59    }
60}
61
62impl FromStr for Signature {
63    type Err = ParseCurveError;
64
65    fn from_str(s: &str) -> Result<Self, Self::Err> {
66        let (curve, data) = if let Some((curve, data)) = s.split_once(':') {
67            (
68                curve.parse().map_err(|_| ParseCurveError::WrongCurveType)?,
69                data,
70            )
71        } else {
72            (CurveType::Ed25519, s)
73        };
74        let decoder = bs58::decode(data.as_bytes());
75        match curve {
76            CurveType::Ed25519 => decoder.into_array_const().map(Self::Ed25519),
77            CurveType::Secp256k1 => decoder.into_array_const().map(Self::Secp256k1),
78            CurveType::P256 => decoder.into_array_const().map(Self::P256),
79        }
80        .map_err(Into::into)
81    }
82}
83
84#[cfg(all(feature = "abi", not(target_arch = "wasm32")))]
85mod abi {
86    use super::*;
87
88    use near_sdk::{
89        schemars::{
90            JsonSchema,
91            r#gen::SchemaGenerator,
92            schema::{InstanceType, Metadata, Schema, SchemaObject},
93        },
94        serde_json,
95    };
96
97    impl JsonSchema for Signature {
98        fn schema_name() -> String {
99            String::schema_name()
100        }
101
102        fn is_referenceable() -> bool {
103            false
104        }
105
106        fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
107            SchemaObject {
108                instance_type: Some(InstanceType::String.into()),
109                extensions: [("contentEncoding", "base58".into())]
110                    .into_iter()
111                    .map(|(k, v)| (k.to_string(), v))
112                    .collect(),
113                metadata: Some(
114                    Metadata {
115                        examples: [Self::example_ed25519(), Self::example_secp256k1()]
116                            .map(serde_json::to_value)
117                            .map(Result::unwrap)
118                            .into(),
119                        ..Default::default()
120                    }
121                    .into(),
122                ),
123                ..Default::default()
124            }
125            .into()
126        }
127    }
128
129    impl Signature {
130        pub(super) fn example_ed25519() -> Self {
131            "ed25519:DNxoVu7L7sHr9pcHGWQoJtPsrwheB8akht1JxaGpc9hGrpehdycXBMLJg4ph1bQ9bXdfoxJCbbwxj3Bdrda52eF"
132                .parse()
133                .unwrap()
134        }
135
136        pub(super) fn example_secp256k1() -> Self {
137            "secp256k1:7huDZxNnibusy6wFkbUBQ9Rqq2VmCKgTWYdJwcPj8VnciHjZKPa41rn5n6WZnMqSUCGRHWMAsMjKGtMVVmpETCeCs"
138                .parse()
139                .unwrap()
140        }
141    }
142}