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