1use std::{cmp::Ordering, fmt, ops::Deref};
2
3use ed25519_compact::x25519;
4use rand::{Rng, SeedableRng};
5use rand_chacha::ChaCha20Rng;
6use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
7use serde_bytes::ByteArray;
8use tagged_base64::{TaggedBase64, Tb64Error};
9
10use crate::traits::signature_key::{PrivateSignatureKey, SignatureKey};
11
12#[derive(Clone, PartialEq, Eq, Hash)]
13pub struct Keypair {
14 pair: x25519::KeyPair,
15}
16
17#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
18#[serde(transparent)]
19pub struct PublicKey {
20 #[serde(
21 serialize_with = "serialize",
22 deserialize_with = "deserialize_x25519_pk"
23 )]
24 key: x25519::PublicKey,
25}
26
27#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
28#[serde(transparent)]
29pub struct SecretKey {
30 #[serde(
31 serialize_with = "serialize",
32 deserialize_with = "deserialize_x25519_sk"
33 )]
34 key: x25519::SecretKey,
35}
36
37impl Keypair {
38 pub fn generate() -> Result<Self, InvalidKeypair> {
39 let pair = x25519::KeyPair::generate();
40 if pair.validate().is_err() {
41 return Err(InvalidKeypair(()));
42 }
43 Ok(Self { pair })
44 }
45
46 pub fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> Result<Self, InvalidKeypair> {
47 let mut hasher = blake3::Hasher::new();
48 hasher.update(&seed);
49 hasher.update(&index.to_be_bytes());
50 let mut rng = ChaCha20Rng::from_seed(*hasher.finalize().as_bytes());
51 let seed: [u8; 32] = rng.r#gen();
52 let sk = x25519::SecretKey::new(seed);
53 let Ok(pk) = sk.recover_public_key() else {
54 return Err(InvalidKeypair(()));
55 };
56 Ok(Self {
57 pair: x25519::KeyPair { sk, pk },
58 })
59 }
60
61 pub fn derive_from<K: SignatureKey>(k: &K::PrivateKey) -> Self {
62 SecretKey::from(blake3::derive_key(
63 "signing key -> x25519 key",
64 &k.to_bytes(),
65 ))
66 .into()
67 }
68
69 pub fn public_key(&self) -> PublicKey {
70 PublicKey { key: self.pair.pk }
71 }
72
73 pub fn secret_key(&self) -> SecretKey {
74 SecretKey {
75 key: self.pair.sk.clone(),
76 }
77 }
78}
79
80impl PublicKey {
81 pub fn as_bytes(&self) -> [u8; 32] {
82 *self.key
83 }
84
85 pub fn as_slice(&self) -> &[u8] {
86 &self.key[..]
87 }
88}
89
90impl SecretKey {
91 pub fn public_key(&self) -> PublicKey {
92 let key = self.key.recover_public_key().expect("valid public key");
93 PublicKey { key }
94 }
95
96 pub fn as_bytes(&self) -> [u8; 32] {
97 *self.key
98 }
99
100 pub fn as_slice(&self) -> &[u8] {
101 &self.key[..]
102 }
103}
104
105impl From<SecretKey> for Keypair {
106 fn from(k: SecretKey) -> Self {
107 let p = k.public_key();
108 Self {
109 pair: x25519::KeyPair {
110 sk: k.key,
111 pk: p.key,
112 },
113 }
114 }
115}
116
117impl From<&SecretKey> for Keypair {
118 fn from(k: &SecretKey) -> Self {
119 Self::from(k.clone())
120 }
121}
122
123impl From<SecretKey> for PublicKey {
124 fn from(k: SecretKey) -> Self {
125 k.public_key()
126 }
127}
128
129impl Ord for PublicKey {
130 fn cmp(&self, other: &Self) -> Ordering {
131 self.key[..].cmp(&other.key[..])
132 }
133}
134
135impl PartialOrd for PublicKey {
136 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
137 Some(self.cmp(other))
138 }
139}
140
141impl fmt::Debug for SecretKey {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 f.write_str("SecretKey")
144 }
145}
146
147impl fmt::Debug for Keypair {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 f.debug_struct("Keypair")
150 .field("public_key", &self.public_key())
151 .field("secret_key", &"SecretKey")
152 .finish()
153 }
154}
155
156impl fmt::Debug for PublicKey {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 write!(f, "{}", bs58::encode(&self.as_bytes()).into_string())
159 }
160}
161
162impl fmt::Display for PublicKey {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 <Self as fmt::Debug>::fmt(self, f)
165 }
166}
167
168impl TryFrom<&[u8]> for PublicKey {
169 type Error = InvalidPublicKey;
170
171 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
172 let key = x25519::PublicKey::from_slice(value).map_err(|_| InvalidPublicKey(()))?;
173 Ok(Self { key })
174 }
175}
176
177impl TryFrom<&[u8]> for SecretKey {
178 type Error = InvalidSecretKey;
179
180 fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
181 let k = x25519::SecretKey::from_slice(s).map_err(|_| InvalidSecretKey(()))?;
182 if k.recover_public_key().is_err() {
183 return Err(InvalidSecretKey(()));
184 }
185 Ok(Self { key: k })
186 }
187}
188
189impl TryFrom<&str> for PublicKey {
190 type Error = InvalidPublicKey;
191
192 fn try_from(s: &str) -> Result<Self, Self::Error> {
193 bs58::decode(s)
194 .into_vec()
195 .map_err(|_| InvalidPublicKey(()))
196 .and_then(|v| PublicKey::try_from(v.as_slice()))
197 }
198}
199
200impl TryFrom<&str> for SecretKey {
201 type Error = InvalidSecretKey;
202
203 fn try_from(s: &str) -> Result<Self, Self::Error> {
204 bs58::decode(s)
205 .into_vec()
206 .map_err(|_| InvalidSecretKey(()))
207 .and_then(|v| SecretKey::try_from(v.as_slice()))
208 }
209}
210
211const X25519_SECRET_KEY: &str = "X25519_SK";
212
213impl TryFrom<TaggedBase64> for SecretKey {
214 type Error = Tb64Error;
215
216 fn try_from(tb: TaggedBase64) -> Result<Self, Self::Error> {
217 if tb.tag() != X25519_SECRET_KEY {
218 return Err(Tb64Error::InvalidTag);
219 }
220 Self::try_from(tb.as_ref()).map_err(|_| Tb64Error::InvalidData)
221 }
222}
223
224impl TryFrom<SecretKey> for TaggedBase64 {
225 type Error = Tb64Error;
226
227 fn try_from(k: SecretKey) -> Result<Self, Self::Error> {
228 TaggedBase64::new(X25519_SECRET_KEY, &k.as_bytes()[..])
229 }
230}
231
232impl From<[u8; 32]> for SecretKey {
233 fn from(bytes: [u8; 32]) -> Self {
234 SecretKey {
235 key: x25519::SecretKey::new(bytes),
236 }
237 }
238}
239
240#[derive(Debug, thiserror::Error)]
241#[error("invalid keypair")]
242pub struct InvalidKeypair(());
243
244#[derive(Debug, thiserror::Error)]
245#[error("invalid secret key")]
246pub struct InvalidSecretKey(());
247
248#[derive(Debug, thiserror::Error)]
249#[error("invalid public key")]
250pub struct InvalidPublicKey(());
251
252fn serialize<S, T, const N: usize>(d: &T, s: S) -> Result<S::Ok, S::Error>
253where
254 S: Serializer,
255 T: Deref<Target = [u8; N]>,
256{
257 if s.is_human_readable() {
258 bs58::encode(**d).into_string().serialize(s)
259 } else {
260 ByteArray::new(**d).serialize(s)
261 }
262}
263
264fn deserialize_x25519_pk<'de, D>(d: D) -> Result<x25519::PublicKey, D::Error>
265where
266 D: Deserializer<'de>,
267{
268 if d.is_human_readable() {
269 let s = String::deserialize(d)?;
270 let mut a = [0; 32];
271 let n = bs58::decode(&s).onto(&mut a).map_err(de::Error::custom)?;
272 x25519::PublicKey::from_slice(&a[..n]).map_err(de::Error::custom)
273 } else {
274 let a = ByteArray::<32>::deserialize(d)?;
275 x25519::PublicKey::from_slice(&a[..]).map_err(de::Error::custom)
276 }
277}
278
279fn deserialize_x25519_sk<'de, D>(d: D) -> Result<x25519::SecretKey, D::Error>
280where
281 D: Deserializer<'de>,
282{
283 if d.is_human_readable() {
284 let s = String::deserialize(d)?;
285 let mut a = [0; 32];
286 let n = bs58::decode(&s).onto(&mut a).map_err(de::Error::custom)?;
287 x25519::SecretKey::from_slice(&a[..n]).map_err(de::Error::custom)
288 } else {
289 let a = ByteArray::<32>::deserialize(d)?;
290 x25519::SecretKey::from_slice(&a[..]).map_err(de::Error::custom)
291 }
292}