defuse_crypto/
signature.rs1use 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}