fire_crypto/signature/
signature.rs1#[cfg(feature = "b64")]
2use crate::error::DecodeError;
3use crate::error::TryFromError;
4
5use std::convert::{TryFrom, TryInto};
6use std::fmt;
7
8use ed25519_dalek as ed;
9
10#[cfg(feature = "b64")]
11use base64::engine::{general_purpose::URL_SAFE_NO_PAD, Engine};
12
13#[derive(Clone, PartialEq, Eq)]
14pub struct Signature {
15 inner: ed::Signature,
16}
17
18impl Signature {
19 pub const LEN: usize = 64;
20
21 pub(crate) fn from_sign(inner: ed::Signature) -> Self {
22 Self { inner }
23 }
24
25 pub fn from_slice(slice: &[u8]) -> Self {
28 slice.try_into().unwrap()
29 }
30
31 pub fn to_bytes(&self) -> [u8; 64] {
32 self.inner.to_bytes()
33 }
34
35 pub(crate) fn inner(&self) -> &ed::Signature {
36 &self.inner
37 }
38}
39
40#[cfg(not(feature = "b64"))]
41impl fmt::Debug for Signature {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 f.debug_tuple("Signature").field(&self.to_bytes()).finish()
44 }
45}
46
47#[cfg(feature = "b64")]
48impl fmt::Debug for Signature {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.debug_tuple("Signature").field(&self.to_string()).finish()
51 }
52}
53
54#[cfg(feature = "b64")]
55impl fmt::Display for Signature {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 base64::display::Base64Display::new(&self.to_bytes(), &URL_SAFE_NO_PAD)
58 .fmt(f)
59 }
60}
61
62impl TryFrom<&[u8]> for Signature {
63 type Error = TryFromError;
64
65 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
66 ed::Signature::try_from(v)
67 .map_err(TryFromError::from_any)
68 .map(Self::from_sign)
69 }
70}
71
72#[cfg(feature = "b64")]
73impl crate::FromStr for Signature {
74 type Err = DecodeError;
75
76 fn from_str(s: &str) -> Result<Self, Self::Err> {
77 if s.len() != crate::calculate_b64_len(Self::LEN) {
78 return Err(DecodeError::InvalidLength);
79 }
80
81 let mut bytes = [0u8; Self::LEN];
82 URL_SAFE_NO_PAD
83 .decode_slice_unchecked(s, &mut bytes)
84 .map_err(DecodeError::inv_bytes)
85 .and_then(|_| {
86 Self::try_from(bytes.as_ref()).map_err(DecodeError::inv_bytes)
87 })
88 }
89}
90
91#[cfg(all(feature = "b64", feature = "serde"))]
92mod impl_serde {
93
94 use super::*;
95
96 use std::borrow::Cow;
97 use std::str::FromStr;
98
99 use _serde::de::Error;
100 use _serde::{Deserialize, Deserializer, Serialize, Serializer};
101
102 impl Serialize for Signature {
103 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104 where
105 S: Serializer,
106 {
107 serializer.collect_str(&self)
108 }
109 }
110
111 impl<'de> Deserialize<'de> for Signature {
112 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 let s: Cow<'_, str> = Deserialize::deserialize(deserializer)?;
117 Self::from_str(s.as_ref()).map_err(D::Error::custom)
118 }
119 }
120}
121
122#[cfg(feature = "protobuf")]
123mod impl_protobuf {
124 use super::*;
125
126 use fire_protobuf::{
127 bytes::BytesWrite,
128 decode::{DecodeError, DecodeMessage, FieldKind},
129 encode::{
130 EncodeError, EncodeMessage, FieldOpt, MessageEncoder, SizeBuilder,
131 },
132 WireType,
133 };
134
135 impl EncodeMessage for Signature {
136 const WIRE_TYPE: WireType = WireType::Len;
137
138 fn is_default(&self) -> bool {
139 false
140 }
141
142 fn encoded_size(
143 &mut self,
144 field: Option<FieldOpt>,
145 builder: &mut SizeBuilder,
146 ) -> Result<(), EncodeError> {
147 self.to_bytes().encoded_size(field, builder)
148 }
149
150 fn encode<B>(
151 &mut self,
152 field: Option<FieldOpt>,
153 encoder: &mut MessageEncoder<B>,
154 ) -> Result<(), EncodeError>
155 where
156 B: BytesWrite,
157 {
158 self.to_bytes().encode(field, encoder)
159 }
160 }
161
162 impl<'m> DecodeMessage<'m> for Signature {
163 const WIRE_TYPE: WireType = WireType::Len;
164
165 fn decode_default() -> Self {
166 Self::from_slice(&[0u8; 32])
167 }
168
169 fn merge(
170 &mut self,
171 kind: FieldKind<'m>,
172 is_field: bool,
173 ) -> Result<(), DecodeError> {
174 let mut t = self.to_bytes();
175 t.merge(kind, is_field)?;
176
177 *self = Self::try_from(t.as_slice())
178 .map_err(|e| DecodeError::Other(e.to_string()))?;
179
180 Ok(())
181 }
182 }
183}
184
185#[cfg(all(feature = "b64", feature = "postgres"))]
186mod impl_postgres {
187 use super::*;
188
189 use bytes::BytesMut;
190 use postgres_types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
191
192 impl ToSql for Signature {
193 fn to_sql(
194 &self,
195 ty: &Type,
196 out: &mut BytesMut,
197 ) -> Result<IsNull, Box<dyn std::error::Error + Sync + Send>>
198 where
199 Self: Sized,
200 {
201 self.to_string().to_sql(ty, out)
202 }
203
204 fn accepts(ty: &Type) -> bool
205 where
206 Self: Sized,
207 {
208 <&str as ToSql>::accepts(ty)
209 }
210
211 to_sql_checked!();
212 }
213
214 impl<'r> FromSql<'r> for Signature {
215 fn from_sql(
216 ty: &Type,
217 raw: &'r [u8],
218 ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> {
219 let s = <&str as FromSql>::from_sql(ty, raw)?;
220 s.parse().map_err(Into::into)
221 }
222
223 fn accepts(ty: &Type) -> bool {
224 <&str as FromSql>::accepts(ty)
225 }
226 }
227}