1use core::fmt;
2use core::ops::{Deref, DerefMut};
3use core::str::FromStr;
4#[cfg(not(target_arch = "wasm32"))]
5use std::{io, path::Path};
6
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9type ParseError = <pkarr::PublicKey as TryFrom<String>>::Error;
10
11fn parse_public_key(value: &str) -> Result<pkarr::PublicKey, ParseError> {
12 let raw = if PublicKey::is_pubky_prefixed(value) {
13 value.strip_prefix("pubky").unwrap_or(value)
14 } else {
15 value
16 };
17 pkarr::PublicKey::try_from(raw.to_string())
18}
19
20#[derive(Clone)]
22pub struct Keypair(pkarr::Keypair);
23
24impl Keypair {
25 #[must_use]
27 pub fn random() -> Self {
28 Self(pkarr::Keypair::random())
29 }
30
31 #[must_use]
33 pub fn secret(&self) -> [u8; 32] {
34 let mut out = [0u8; 32];
35 out.copy_from_slice(self.0.secret_key().as_ref());
36 out
37 }
38
39 #[must_use]
41 pub fn from_secret(secret: &[u8; 32]) -> Self {
42 Self(pkarr::Keypair::from_secret_key(secret))
43 }
44
45 #[cfg(not(target_arch = "wasm32"))]
47 pub fn from_secret_key_file(path: &Path) -> Result<Self, io::Error> {
48 pkarr::Keypair::from_secret_key_file(path).map(Self)
49 }
50
51 #[must_use]
56 pub fn public_key(&self) -> PublicKey {
57 PublicKey(self.0.public_key())
58 }
59
60 #[must_use]
62 pub const fn as_inner(&self) -> &pkarr::Keypair {
63 &self.0
64 }
65
66 #[cfg(not(target_arch = "wasm32"))]
68 pub fn write_secret_key_file(&self, path: &Path) -> Result<(), io::Error> {
69 self.0.write_secret_key_file(path)
70 }
71
72 #[must_use]
74 pub fn into_inner(self) -> pkarr::Keypair {
75 self.0
76 }
77}
78
79impl fmt::Debug for Keypair {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 self.0.fmt(f)
82 }
83}
84
85impl Deref for Keypair {
86 type Target = pkarr::Keypair;
87
88 fn deref(&self) -> &Self::Target {
89 &self.0
90 }
91}
92
93impl DerefMut for Keypair {
94 fn deref_mut(&mut self) -> &mut Self::Target {
95 &mut self.0
96 }
97}
98
99impl From<pkarr::Keypair> for Keypair {
100 fn from(keypair: pkarr::Keypair) -> Self {
101 Self(keypair)
102 }
103}
104
105impl From<Keypair> for pkarr::Keypair {
106 fn from(value: Keypair) -> Self {
107 value.0
108 }
109}
110
111#[derive(Clone, PartialEq, Eq, Hash)]
116pub struct PublicKey(pkarr::PublicKey);
117
118impl PublicKey {
119 pub fn is_pubky_prefixed(value: &str) -> bool {
121 matches!(value.strip_prefix("pubky"), Some(stripped) if stripped.len() == 52)
122 }
123
124 #[must_use]
126 pub const fn as_inner(&self) -> &pkarr::PublicKey {
127 &self.0
128 }
129
130 #[must_use]
132 pub fn into_inner(self) -> pkarr::PublicKey {
133 self.0
134 }
135
136 #[must_use]
141 pub fn z32(&self) -> String {
142 self.0.to_string()
143 }
144
145 pub fn try_from_z32(value: &str) -> Result<Self, ParseError> {
147 pkarr::PublicKey::try_from(value.to_string()).map(Self)
148 }
149}
150
151impl fmt::Display for PublicKey {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "pubky{}", self.z32())
154 }
155}
156
157impl fmt::Debug for PublicKey {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 f.debug_tuple("PublicKey").field(&self.to_string()).finish()
160 }
161}
162
163impl Serialize for PublicKey {
164 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
165 if serializer.is_human_readable() {
166 serializer.serialize_str(&self.z32())
167 } else {
168 self.0.serialize(serializer)
169 }
170 }
171}
172
173impl<'de> Deserialize<'de> for PublicKey {
174 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
175 if deserializer.is_human_readable() {
176 let value = String::deserialize(deserializer)?;
177 Self::try_from_z32(&value).map_err(serde::de::Error::custom)
178 } else {
179 pkarr::PublicKey::deserialize(deserializer).map(Self)
180 }
181 }
182}
183
184impl Deref for PublicKey {
185 type Target = pkarr::PublicKey;
186
187 fn deref(&self) -> &Self::Target {
188 &self.0
189 }
190}
191
192impl From<pkarr::PublicKey> for PublicKey {
193 fn from(value: pkarr::PublicKey) -> Self {
194 Self(value)
195 }
196}
197
198impl From<&pkarr::PublicKey> for PublicKey {
199 fn from(value: &pkarr::PublicKey) -> Self {
200 Self(value.clone())
201 }
202}
203
204impl From<PublicKey> for pkarr::PublicKey {
205 fn from(value: PublicKey) -> Self {
206 value.0
207 }
208}
209
210impl From<&PublicKey> for pkarr::PublicKey {
211 fn from(value: &PublicKey) -> Self {
212 value.0.clone()
213 }
214}
215
216impl TryFrom<&str> for PublicKey {
217 type Error = ParseError;
218
219 fn try_from(value: &str) -> Result<Self, Self::Error> {
220 parse_public_key(value).map(Self)
221 }
222}
223
224impl TryFrom<&String> for PublicKey {
225 type Error = ParseError;
226
227 fn try_from(value: &String) -> Result<Self, Self::Error> {
228 parse_public_key(value).map(Self)
229 }
230}
231
232impl TryFrom<String> for PublicKey {
233 type Error = ParseError;
234
235 fn try_from(value: String) -> Result<Self, Self::Error> {
236 parse_public_key(&value).map(Self)
237 }
238}
239
240impl FromStr for PublicKey {
241 type Err = ParseError;
242
243 fn from_str(s: &str) -> Result<Self, Self::Err> {
244 parse_public_key(s).map(Self)
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn public_key_serializes_as_z32() {
254 let public_key = Keypair::random().public_key();
255
256 let json = serde_json::to_string(&public_key).unwrap();
257
258 assert_eq!(json, format!("\"{}\"", public_key.z32()));
259 }
260
261 #[test]
262 fn public_key_deserializes_from_z32() {
263 let public_key = Keypair::random().public_key();
264 let json = format!("\"{}\"", public_key.z32());
265
266 let parsed: PublicKey = serde_json::from_str(&json).unwrap();
267
268 assert_eq!(parsed, public_key);
269 }
270
271 #[test]
272 fn public_key_display_uses_pubky_prefix() {
273 let public_key = Keypair::random().public_key();
274
275 assert_eq!(public_key.to_string(), format!("pubky{}", public_key.z32()));
276 }
277}