fire_crypto/cipher/
public_key.rs1#[cfg(feature = "b64")]
2use crate::error::DecodeError;
3use crate::error::TryFromError;
4
5use std::convert::{TryFrom, TryInto};
6use std::hash::{Hash, Hasher};
7use std::{cmp, fmt};
8
9use x25519_dalek as x;
10
11#[cfg(feature = "b64")]
12use base64::engine::{general_purpose::URL_SAFE_NO_PAD, Engine};
13
14#[derive(Clone)]
15pub struct PublicKey {
16 pub inner: x::PublicKey,
17}
18
19impl PublicKey {
20 pub const LEN: usize = 32;
21
22 pub(crate) fn from_ephemeral_secret(secret: &x::EphemeralSecret) -> Self {
23 Self {
24 inner: secret.into(),
25 }
26 }
27
28 pub(crate) fn from_static_secret(secret: &x::StaticSecret) -> Self {
29 Self {
30 inner: secret.into(),
31 }
32 }
33
34 pub fn from_slice(slice: &[u8]) -> Self {
37 slice.try_into().unwrap()
38 }
39
40 pub fn to_bytes(&self) -> [u8; 32] {
41 self.as_ref().try_into().unwrap()
42 }
43
44 pub fn inner(&self) -> &x::PublicKey {
45 &self.inner
46 }
47}
48
49#[cfg(not(feature = "b64"))]
50impl fmt::Debug for PublicKey {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 f.debug_tuple("PublicKey").field(&self.as_ref()).finish()
53 }
54}
55
56#[cfg(feature = "b64")]
57impl fmt::Debug for PublicKey {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 f.debug_tuple("PublicKey").field(&self.to_string()).finish()
60 }
61}
62
63#[cfg(feature = "b64")]
64impl fmt::Display for PublicKey {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 base64::display::Base64Display::new(self.as_ref(), &URL_SAFE_NO_PAD)
67 .fmt(f)
68 }
69}
70
71impl cmp::PartialEq for PublicKey {
72 fn eq(&self, other: &PublicKey) -> bool {
73 self.as_ref() == other.as_ref()
74 }
75}
76
77impl cmp::Eq for PublicKey {}
78
79impl Hash for PublicKey {
80 fn hash<H: Hasher>(&self, state: &mut H) {
81 self.as_ref().hash(state)
82 }
83}
84
85impl From<[u8; 32]> for PublicKey {
86 fn from(bytes: [u8; 32]) -> Self {
87 Self {
88 inner: bytes.into(),
89 }
90 }
91}
92
93impl TryFrom<&[u8]> for PublicKey {
94 type Error = TryFromError;
95
96 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
97 <[u8; 32]>::try_from(v)
98 .map_err(TryFromError::from_any)
99 .map(Self::from)
100 }
101}
102
103#[cfg(feature = "b64")]
104impl crate::FromStr for PublicKey {
105 type Err = DecodeError;
106
107 fn from_str(s: &str) -> Result<Self, Self::Err> {
108 if s.len() != crate::calculate_b64_len(Self::LEN) {
109 return Err(DecodeError::InvalidLength);
110 }
111
112 let mut bytes = [0u8; Self::LEN];
113 URL_SAFE_NO_PAD
114 .decode_slice_unchecked(s, &mut bytes)
115 .map_err(DecodeError::inv_bytes)
116 .and_then(|_| {
117 Self::try_from(bytes.as_ref()).map_err(DecodeError::inv_bytes)
118 })
119 }
120}
121
122impl AsRef<[u8]> for PublicKey {
123 fn as_ref(&self) -> &[u8] {
124 self.inner.as_bytes()
125 }
126}
127
128#[cfg(all(feature = "b64", feature = "serde"))]
129mod impl_serde {
130
131 use super::*;
132
133 use std::borrow::Cow;
134 use std::str::FromStr;
135
136 use _serde::de::Error;
137 use _serde::{Deserialize, Deserializer, Serialize, Serializer};
138
139 impl Serialize for PublicKey {
140 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
141 where
142 S: Serializer,
143 {
144 serializer.collect_str(&self)
145 }
146 }
147
148 impl<'de> Deserialize<'de> for PublicKey {
149 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150 where
151 D: Deserializer<'de>,
152 {
153 let s: Cow<'_, str> = Deserialize::deserialize(deserializer)?;
154 Self::from_str(s.as_ref()).map_err(D::Error::custom)
155 }
156 }
157}
158
159#[cfg(all(feature = "b64", feature = "postgres"))]
160mod impl_postgres {
161 use super::*;
162
163 use bytes::BytesMut;
164 use postgres_types::{to_sql_checked, FromSql, IsNull, ToSql, Type};
165
166 impl ToSql for PublicKey {
167 fn to_sql(
168 &self,
169 ty: &Type,
170 out: &mut BytesMut,
171 ) -> Result<IsNull, Box<dyn std::error::Error + Sync + Send>>
172 where
173 Self: Sized,
174 {
175 self.to_string().to_sql(ty, out)
176 }
177
178 fn accepts(ty: &Type) -> bool
179 where
180 Self: Sized,
181 {
182 <&str as ToSql>::accepts(ty)
183 }
184
185 to_sql_checked!();
186 }
187
188 impl<'r> FromSql<'r> for PublicKey {
189 fn from_sql(
190 ty: &Type,
191 raw: &'r [u8],
192 ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> {
193 let s = <&str as FromSql>::from_sql(ty, raw)?;
194 s.parse().map_err(Into::into)
195 }
196
197 fn accepts(ty: &Type) -> bool {
198 <&str as FromSql>::accepts(ty)
199 }
200 }
201}