fire_crypto/signature/
signature.rs

1#[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	/// ## Panics
26	/// if the slice is not 64 bytes long.
27	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}