hotshot_types/
x25519.rs

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}