stellar_strkey/
ed25519.rs

1use crate::{
2    convert::{decode, encode},
3    error::DecodeError,
4    version,
5};
6
7use alloc::{format, string::String, vec, vec::Vec};
8use core::{
9    fmt::{Debug, Display},
10    str::FromStr,
11};
12
13#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
14#[cfg_attr(
15    feature = "serde",
16    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
17)]
18pub struct PrivateKey(pub [u8; 32]);
19
20impl Debug for PrivateKey {
21    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
22        write!(f, "PrivateKey(")?;
23        write!(
24            f,
25            "{}",
26            &self
27                .0
28                .iter()
29                .map(|b| format!("{b:02x}"))
30                .collect::<String>()
31        )?;
32        write!(f, ")")?;
33        Ok(())
34    }
35}
36
37impl PrivateKey {
38    pub fn to_string(&self) -> String {
39        encode(version::PRIVATE_KEY_ED25519, &self.0)
40    }
41
42    pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
43        match payload.try_into() {
44            Ok(ed25519) => Ok(Self(ed25519)),
45            Err(_) => Err(DecodeError::Invalid),
46        }
47    }
48
49    pub fn from_string(s: &str) -> Result<Self, DecodeError> {
50        let (ver, payload) = decode(s)?;
51        match ver {
52            version::PRIVATE_KEY_ED25519 => Self::from_payload(&payload),
53            _ => Err(DecodeError::Invalid),
54        }
55    }
56}
57
58impl Display for PrivateKey {
59    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60        write!(f, "{}", self.to_string())
61    }
62}
63
64impl FromStr for PrivateKey {
65    type Err = DecodeError;
66
67    fn from_str(s: &str) -> Result<Self, Self::Err> {
68        PrivateKey::from_string(s)
69    }
70}
71
72#[cfg(feature = "serde-decoded")]
73mod private_key_decoded_serde_impl {
74    use super::*;
75    use crate::decoded_json_format::Decoded;
76    use serde::{Deserialize, Deserializer, Serialize, Serializer};
77    use serde_with::serde_as;
78
79    #[serde_as]
80    #[derive(Serialize)]
81    #[serde(transparent)]
82    struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
83
84    #[serde_as]
85    #[derive(Deserialize)]
86    #[serde(transparent)]
87    struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
88
89    impl Serialize for Decoded<&PrivateKey> {
90        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
91            let Self(PrivateKey(bytes)) = self;
92            DecodedBorrowed(bytes).serialize(serializer)
93        }
94    }
95
96    impl<'de> Deserialize<'de> for Decoded<PrivateKey> {
97        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
98            let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
99            Ok(Decoded(PrivateKey(bytes)))
100        }
101    }
102}
103
104#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
105#[cfg_attr(
106    feature = "serde",
107    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
108)]
109pub struct PublicKey(pub [u8; 32]);
110
111impl Debug for PublicKey {
112    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113        write!(f, "PublicKey(")?;
114        write!(
115            f,
116            "{}",
117            &self
118                .0
119                .iter()
120                .map(|b| format!("{b:02x}"))
121                .collect::<String>()
122        )?;
123        write!(f, ")")?;
124        Ok(())
125    }
126}
127
128impl PublicKey {
129    pub fn to_string(&self) -> String {
130        encode(version::PUBLIC_KEY_ED25519, &self.0)
131    }
132
133    pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
134        match payload.try_into() {
135            Ok(ed25519) => Ok(Self(ed25519)),
136            Err(_) => Err(DecodeError::Invalid),
137        }
138    }
139
140    pub fn from_string(s: &str) -> Result<Self, DecodeError> {
141        let (ver, payload) = decode(s)?;
142        match ver {
143            version::PUBLIC_KEY_ED25519 => Self::from_payload(&payload),
144            _ => Err(DecodeError::Invalid),
145        }
146    }
147}
148
149impl Display for PublicKey {
150    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
151        write!(f, "{}", self.to_string())
152    }
153}
154
155impl FromStr for PublicKey {
156    type Err = DecodeError;
157
158    fn from_str(s: &str) -> Result<Self, Self::Err> {
159        PublicKey::from_string(s)
160    }
161}
162
163#[cfg(feature = "serde-decoded")]
164mod public_key_decoded_serde_impl {
165    use super::*;
166    use crate::decoded_json_format::Decoded;
167    use serde::{Deserialize, Deserializer, Serialize, Serializer};
168    use serde_with::serde_as;
169
170    #[serde_as]
171    #[derive(Serialize)]
172    #[serde(transparent)]
173    struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
174
175    #[serde_as]
176    #[derive(Deserialize)]
177    #[serde(transparent)]
178    struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
179
180    impl Serialize for Decoded<&PublicKey> {
181        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
182            let Self(PublicKey(bytes)) = self;
183            DecodedBorrowed(bytes).serialize(serializer)
184        }
185    }
186
187    impl<'de> Deserialize<'de> for Decoded<PublicKey> {
188        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
189            let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
190            Ok(Decoded(PublicKey(bytes)))
191        }
192    }
193}
194
195#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
196#[cfg_attr(
197    feature = "serde",
198    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
199)]
200pub struct MuxedAccount {
201    pub ed25519: [u8; 32],
202    pub id: u64,
203}
204
205impl Debug for MuxedAccount {
206    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
207        write!(f, "MuxedAccount(")?;
208        write!(
209            f,
210            "{}",
211            &self
212                .ed25519
213                .iter()
214                .map(|b| format!("{b:02x}"))
215                .collect::<String>()
216        )?;
217        write!(f, ", ")?;
218        write!(f, "{}", self.id)?;
219        write!(f, ")")?;
220        Ok(())
221    }
222}
223
224impl MuxedAccount {
225    pub fn to_string(&self) -> String {
226        let mut payload: [u8; 40] = [0; 40];
227        let (ed25519, id) = payload.split_at_mut(32);
228        ed25519.copy_from_slice(&self.ed25519);
229        id.copy_from_slice(&self.id.to_be_bytes());
230        encode(version::MUXED_ACCOUNT_ED25519, &payload)
231    }
232
233    pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
234        if payload.len() < 40 {
235            return Err(DecodeError::Invalid);
236        }
237        let (ed25519, id) = payload.split_at(32);
238        Ok(Self {
239            ed25519: ed25519.try_into().map_err(|_| DecodeError::Invalid)?,
240            id: u64::from_be_bytes(id.try_into().map_err(|_| DecodeError::Invalid)?),
241        })
242    }
243
244    pub fn from_string(s: &str) -> Result<Self, DecodeError> {
245        let (ver, payload) = decode(s)?;
246        match ver {
247            version::MUXED_ACCOUNT_ED25519 => Self::from_payload(&payload),
248            _ => Err(DecodeError::Invalid),
249        }
250    }
251}
252
253impl Display for MuxedAccount {
254    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
255        write!(f, "{}", self.to_string())
256    }
257}
258
259impl FromStr for MuxedAccount {
260    type Err = DecodeError;
261
262    fn from_str(s: &str) -> Result<Self, Self::Err> {
263        MuxedAccount::from_string(s)
264    }
265}
266
267#[cfg(feature = "serde-decoded")]
268mod muxed_account_decoded_serde_impl {
269    use super::*;
270    use crate::decoded_json_format::Decoded;
271    use serde::{Deserialize, Deserializer, Serialize, Serializer};
272    use serde_with::serde_as;
273
274    #[serde_as]
275    #[derive(Serialize)]
276    struct DecodedBorrowed<'a> {
277        #[serde_as(as = "serde_with::hex::Hex")]
278        ed25519: &'a [u8; 32],
279        id: u64,
280    }
281
282    #[serde_as]
283    #[derive(Deserialize)]
284    struct DecodedOwned {
285        #[serde_as(as = "serde_with::hex::Hex")]
286        ed25519: [u8; 32],
287        id: u64,
288    }
289
290    impl Serialize for Decoded<&MuxedAccount> {
291        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
292            let Self(MuxedAccount { ed25519, id }) = self;
293            DecodedBorrowed { ed25519, id: *id }.serialize(serializer)
294        }
295    }
296
297    impl<'de> Deserialize<'de> for Decoded<MuxedAccount> {
298        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
299            let DecodedOwned { ed25519, id } = DecodedOwned::deserialize(deserializer)?;
300            Ok(Decoded(MuxedAccount { ed25519, id }))
301        }
302    }
303}
304
305/// Stores a signed payload ed25519 signer.
306///
307/// The payload must not have a size larger than u32::MAX.
308#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
309#[cfg_attr(
310    feature = "serde",
311    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
312)]
313pub struct SignedPayload {
314    pub ed25519: [u8; 32],
315    pub payload: Vec<u8>,
316}
317
318impl Debug for SignedPayload {
319    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
320        write!(f, "SignedPayload(")?;
321        write!(
322            f,
323            "{}",
324            &self
325                .ed25519
326                .iter()
327                .map(|b| format!("{b:02x}"))
328                .collect::<String>()
329        )?;
330        write!(f, ", ")?;
331        write!(
332            f,
333            "{}",
334            &self
335                .payload
336                .iter()
337                .map(|b| format!("{b:02x}"))
338                .collect::<String>()
339        )?;
340        write!(f, ")")?;
341        Ok(())
342    }
343}
344
345impl SignedPayload {
346    /// Returns the strkey string for the signed payload signer.
347    ///
348    /// ### Panics
349    ///
350    /// When the payload is larger than u32::MAX.
351    pub fn to_string(&self) -> String {
352        let inner_payload_len = self.payload.len();
353        let payload_len = 32 + 4 + inner_payload_len + (4 - inner_payload_len % 4) % 4;
354
355        let inner_payload_len_u32: u32 = inner_payload_len
356            .try_into()
357            .expect("payload length larger than u32::MAX");
358
359        let mut payload = vec![0; payload_len];
360        payload[..32].copy_from_slice(&self.ed25519);
361        payload[32..32 + 4].copy_from_slice(&(inner_payload_len_u32).to_be_bytes());
362        payload[32 + 4..32 + 4 + inner_payload_len].copy_from_slice(&self.payload);
363
364        encode(version::SIGNED_PAYLOAD_ED25519, &payload)
365    }
366
367    pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
368        // 32-byte for the signer, 4-byte for the payload size, then either 4-byte for the
369        // min or 64-byte for the max payload
370        const MAX_INNER_PAYLOAD_LENGTH: u32 = 64;
371        const MIN_LENGTH: usize = 32 + 4 + 4;
372        const MAX_LENGTH: usize = 32 + 4 + (MAX_INNER_PAYLOAD_LENGTH as usize);
373        let payload_len = payload.len();
374        if !(MIN_LENGTH..=MAX_LENGTH).contains(&payload_len) {
375            return Err(DecodeError::Invalid);
376        }
377
378        // Decode ed25519 public key. 32 bytes.
379        let mut offset = 0;
380        let ed25519: [u8; 32] = payload
381            .get(offset..offset + 32)
382            .ok_or(DecodeError::Invalid)?
383            .try_into()
384            .map_err(|_| DecodeError::Invalid)?;
385        offset += 32;
386
387        // Decode inner payload length. 4 bytes.
388        let inner_payload_len = u32::from_be_bytes(
389            payload
390                .get(offset..offset + 4)
391                .ok_or(DecodeError::Invalid)?
392                .try_into()
393                .map_err(|_| DecodeError::Invalid)?,
394        );
395        offset += 4;
396
397        // Check inner payload length is inside accepted range.
398        if inner_payload_len > MAX_INNER_PAYLOAD_LENGTH {
399            return Err(DecodeError::Invalid);
400        }
401
402        // Decode inner payload.
403        let inner_payload = payload
404            .get(offset..offset + inner_payload_len as usize)
405            .ok_or(DecodeError::Invalid)?;
406        offset += inner_payload_len as usize;
407
408        // Calculate padding at end of inner payload. 0-3 bytes.
409        let padding_len = (4 - inner_payload_len % 4) % 4;
410
411        // Decode padding.
412        let padding = payload
413            .get(offset..offset + padding_len as usize)
414            .ok_or(DecodeError::Invalid)?;
415        offset += padding_len as usize;
416
417        // Check padding is all zeros.
418        if padding.iter().any(|b| *b != 0) {
419            return Err(DecodeError::Invalid);
420        }
421
422        // Check that entire payload consumed.
423        if offset != payload_len {
424            return Err(DecodeError::Invalid);
425        }
426
427        Ok(Self {
428            ed25519,
429            payload: inner_payload.to_vec(),
430        })
431    }
432
433    pub fn from_string(s: &str) -> Result<Self, DecodeError> {
434        let (ver, payload) = decode(s)?;
435        match ver {
436            version::SIGNED_PAYLOAD_ED25519 => Self::from_payload(&payload),
437            _ => Err(DecodeError::Invalid),
438        }
439    }
440}
441
442impl Display for SignedPayload {
443    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
444        write!(f, "{}", self.to_string())
445    }
446}
447
448impl FromStr for SignedPayload {
449    type Err = DecodeError;
450
451    fn from_str(s: &str) -> Result<Self, Self::Err> {
452        SignedPayload::from_string(s)
453    }
454}
455
456#[cfg(feature = "serde-decoded")]
457mod signed_payload_decoded_serde_impl {
458    use super::*;
459    use crate::decoded_json_format::Decoded;
460    use serde::{Deserialize, Deserializer, Serialize, Serializer};
461    use serde_with::serde_as;
462
463    #[serde_as]
464    #[derive(Serialize)]
465    struct DecodedBorrowed<'a> {
466        #[serde_as(as = "serde_with::hex::Hex")]
467        ed25519: &'a [u8; 32],
468        #[serde_as(as = "serde_with::hex::Hex")]
469        payload: &'a [u8],
470    }
471
472    #[serde_as]
473    #[derive(Deserialize)]
474    struct DecodedOwned {
475        #[serde_as(as = "serde_with::hex::Hex")]
476        ed25519: [u8; 32],
477        #[serde_as(as = "serde_with::hex::Hex")]
478        payload: Vec<u8>,
479    }
480
481    impl Serialize for Decoded<&SignedPayload> {
482        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
483            let Self(SignedPayload { ed25519, payload }) = self;
484            DecodedBorrowed { ed25519, payload }.serialize(serializer)
485        }
486    }
487
488    impl<'de> Deserialize<'de> for Decoded<SignedPayload> {
489        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
490            let DecodedOwned { ed25519, payload } = DecodedOwned::deserialize(deserializer)?;
491            Ok(Decoded(SignedPayload { ed25519, payload }))
492        }
493    }
494}