1use crate::{
2 convert::{binary_len, decode, decode_zeroizing, encode, encode_len, encode_zeroizing},
3 error::DecodeError,
4 unredacted::Unredacted,
5 version,
6};
7
8use core::{
9 fmt::{Debug, Display},
10 str::FromStr,
11};
12use heapless::{String, Vec};
13use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
14
15#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Zeroize, ZeroizeOnDrop)]
32#[cfg_attr(feature = "serde", derive(serde_with::DeserializeFromStr))]
33pub struct PrivateKey(pub [u8; 32]);
34
35impl Debug for PrivateKey {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 f.write_str("PrivateKey([REDACTED])")
38 }
39}
40
41impl PrivateKey {
42 pub(crate) const PAYLOAD_LEN: usize = 32;
43 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
44 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
45 const _ASSERTS: () = {
46 assert!(Self::BINARY_LEN == 35);
47 assert!(Self::ENCODED_LEN == 56);
48 };
49}
50
51impl Unredacted<&PrivateKey> {
52 pub fn to_string(&self) -> String<{ PrivateKey::ENCODED_LEN }> {
61 let mut zeroizing: Zeroizing<String<{ PrivateKey::ENCODED_LEN }>> =
62 Zeroizing::new(String::new());
63 self.write_string(&mut zeroizing);
64 let mut out: String<{ PrivateKey::ENCODED_LEN }> = String::new();
65 out.push_str(&zeroizing).unwrap();
66 out
67 }
68
69 pub fn write_string(&self, out: &mut Zeroizing<String<{ PrivateKey::ENCODED_LEN }>>) {
79 encode_zeroizing::<
80 { PrivateKey::PAYLOAD_LEN },
81 { PrivateKey::BINARY_LEN },
82 { PrivateKey::ENCODED_LEN },
83 >(version::PRIVATE_KEY_ED25519, &self.0 .0, out);
84 }
85}
86
87impl PrivateKey {
88 pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
89 match payload.try_into() {
90 Ok(ed25519) => Ok(Self(ed25519)),
91 Err(_) => Err(DecodeError::InvalidPayloadLength),
92 }
93 }
94
95 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
96 Self::from_slice(s.as_bytes())
97 }
98
99 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
100 let mut payload: Zeroizing<Vec<u8, { Self::PAYLOAD_LEN }>> = Zeroizing::new(Vec::new());
101 let ver = decode_zeroizing::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s, &mut payload)?;
102 match ver {
103 version::PRIVATE_KEY_ED25519 => Self::from_payload(&payload),
104 _ => Err(DecodeError::UnsupportedVersion),
105 }
106 }
107
108 pub fn as_unredacted(&self) -> Unredacted<&Self> {
112 Unredacted(self)
113 }
114}
115
116impl Display for Unredacted<&PrivateKey> {
117 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118 let mut buf: Zeroizing<String<{ PrivateKey::ENCODED_LEN }>> = Zeroizing::new(String::new());
119 self.write_string(&mut buf);
120 f.write_str(&buf)
121 }
122}
123
124impl Debug for Unredacted<&PrivateKey> {
125 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
126 write!(f, "PrivateKey(")?;
127 for b in &self.0 .0 {
128 write!(f, "{b:02x}")?;
129 }
130 write!(f, ")")
131 }
132}
133
134impl Display for Unredacted<PrivateKey> {
135 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136 Display::fmt(&Unredacted(&self.0), f)
137 }
138}
139
140impl Debug for Unredacted<PrivateKey> {
141 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142 Debug::fmt(&Unredacted(&self.0), f)
143 }
144}
145
146impl FromStr for PrivateKey {
147 type Err = DecodeError;
148
149 fn from_str(s: &str) -> Result<Self, Self::Err> {
150 PrivateKey::from_string(s)
151 }
152}
153
154#[cfg(feature = "serde-decoded")]
155mod private_key_decoded_serde_impl {
156 use super::*;
157 use crate::{decoded_json_format::Decoded, unredacted::Unredacted};
158 use serde::{Deserialize, Deserializer, Serialize, Serializer};
159 use serde_with::serde_as;
160
161 #[serde_as]
162 #[derive(Serialize)]
163 #[serde(transparent)]
164 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
165
166 #[serde_as]
167 #[derive(Deserialize)]
168 #[serde(transparent)]
169 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
170
171 impl Serialize for Decoded<Unredacted<&PrivateKey>> {
172 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
173 let Self(Unredacted(PrivateKey(bytes))) = self;
174 DecodedBorrowed(bytes).serialize(serializer)
175 }
176 }
177
178 impl<'de> Deserialize<'de> for Decoded<Unredacted<PrivateKey>> {
179 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
180 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
181 Ok(Decoded(Unredacted(PrivateKey(bytes))))
182 }
183 }
184}
185
186#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
188#[cfg_attr(
189 feature = "serde",
190 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
191)]
192pub struct PublicKey(pub [u8; 32]);
193
194impl Debug for PublicKey {
195 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
196 write!(f, "PublicKey(")?;
197 for b in &self.0 {
198 write!(f, "{b:02x}")?;
199 }
200 write!(f, ")")
201 }
202}
203
204impl PublicKey {
205 pub(crate) const PAYLOAD_LEN: usize = 32;
206 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
207 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
208 const _ASSERTS: () = {
209 assert!(Self::BINARY_LEN == 35);
210 assert!(Self::ENCODED_LEN == 56);
211 };
212
213 pub fn to_string(&self) -> String<{ Self::ENCODED_LEN }> {
214 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
215 version::PUBLIC_KEY_ED25519,
216 &self.0,
217 )
218 }
219
220 pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
221 match payload.try_into() {
222 Ok(ed25519) => Ok(Self(ed25519)),
223 Err(_) => Err(DecodeError::InvalidPayloadLength),
224 }
225 }
226
227 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
228 Self::from_slice(s.as_bytes())
229 }
230
231 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
232 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
233 match ver {
234 version::PUBLIC_KEY_ED25519 => Self::from_payload(&payload),
235 _ => Err(DecodeError::UnsupportedVersion),
236 }
237 }
238}
239
240impl Display for PublicKey {
241 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 write!(f, "{}", self.to_string())
243 }
244}
245
246impl FromStr for PublicKey {
247 type Err = DecodeError;
248
249 fn from_str(s: &str) -> Result<Self, Self::Err> {
250 PublicKey::from_string(s)
251 }
252}
253
254#[cfg(feature = "serde-decoded")]
255mod public_key_decoded_serde_impl {
256 use super::*;
257 use crate::decoded_json_format::Decoded;
258 use serde::{Deserialize, Deserializer, Serialize, Serializer};
259 use serde_with::serde_as;
260
261 #[serde_as]
262 #[derive(Serialize)]
263 #[serde(transparent)]
264 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
265
266 #[serde_as]
267 #[derive(Deserialize)]
268 #[serde(transparent)]
269 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
270
271 impl Serialize for Decoded<&PublicKey> {
272 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
273 let Self(PublicKey(bytes)) = self;
274 DecodedBorrowed(bytes).serialize(serializer)
275 }
276 }
277
278 impl<'de> Deserialize<'de> for Decoded<PublicKey> {
279 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
280 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
281 Ok(Decoded(PublicKey(bytes)))
282 }
283 }
284}
285
286#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
288#[cfg_attr(
289 feature = "serde",
290 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
291)]
292pub struct MuxedAccount {
293 pub ed25519: [u8; 32],
294 pub id: u64,
295}
296
297impl Debug for MuxedAccount {
298 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
299 write!(f, "MuxedAccount(")?;
300 for b in &self.ed25519 {
301 write!(f, "{b:02x}")?;
302 }
303 write!(f, ", {}", self.id)?;
304 write!(f, ")")
305 }
306}
307
308impl MuxedAccount {
309 pub(crate) const PAYLOAD_LEN: usize = 32 + 8; pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
311 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
312 const _ASSERTS: () = {
313 assert!(Self::BINARY_LEN == 43);
314 assert!(Self::ENCODED_LEN == 69);
315 };
316
317 pub fn to_string(&self) -> String<{ Self::ENCODED_LEN }> {
318 let mut payload: [u8; Self::PAYLOAD_LEN] = [0; Self::PAYLOAD_LEN];
319 let (ed25519, id) = payload.split_at_mut(32);
320 ed25519.copy_from_slice(&self.ed25519);
321 id.copy_from_slice(&self.id.to_be_bytes());
322 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
323 version::MUXED_ACCOUNT_ED25519,
324 &payload,
325 )
326 }
327
328 pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
329 if payload.len() != 40 {
330 return Err(DecodeError::InvalidPayloadLength);
331 }
332 let (ed25519, id) = payload.split_at(32);
333 Ok(Self {
334 ed25519: ed25519
335 .try_into()
336 .map_err(|_| DecodeError::InvalidPayloadLength)?,
337 id: u64::from_be_bytes(
338 id.try_into()
339 .map_err(|_| DecodeError::InvalidPayloadLength)?,
340 ),
341 })
342 }
343
344 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
345 Self::from_slice(s.as_bytes())
346 }
347
348 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
349 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
350 match ver {
351 version::MUXED_ACCOUNT_ED25519 => Self::from_payload(&payload),
352 _ => Err(DecodeError::UnsupportedVersion),
353 }
354 }
355}
356
357impl Display for MuxedAccount {
358 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
359 write!(f, "{}", self.to_string())
360 }
361}
362
363impl FromStr for MuxedAccount {
364 type Err = DecodeError;
365
366 fn from_str(s: &str) -> Result<Self, Self::Err> {
367 MuxedAccount::from_string(s)
368 }
369}
370
371#[cfg(feature = "serde-decoded")]
372mod muxed_account_decoded_serde_impl {
373 use super::*;
374 use crate::decoded_json_format::Decoded;
375 use serde::{Deserialize, Deserializer, Serialize, Serializer};
376 use serde_with::serde_as;
377
378 #[serde_as]
379 #[derive(Serialize)]
380 struct DecodedBorrowed<'a> {
381 #[serde_as(as = "serde_with::hex::Hex")]
382 ed25519: &'a [u8; 32],
383 id: u64,
384 }
385
386 #[serde_as]
387 #[derive(Deserialize)]
388 struct DecodedOwned {
389 #[serde_as(as = "serde_with::hex::Hex")]
390 ed25519: [u8; 32],
391 id: u64,
392 }
393
394 impl Serialize for Decoded<&MuxedAccount> {
395 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
396 let Self(MuxedAccount { ed25519, id }) = self;
397 DecodedBorrowed { ed25519, id: *id }.serialize(serializer)
398 }
399 }
400
401 impl<'de> Deserialize<'de> for Decoded<MuxedAccount> {
402 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
403 let DecodedOwned { ed25519, id } = DecodedOwned::deserialize(deserializer)?;
404 Ok(Decoded(MuxedAccount { ed25519, id }))
405 }
406 }
407}
408
409#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
414#[cfg_attr(
415 feature = "serde",
416 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
417)]
418pub struct SignedPayload {
419 ed25519: [u8; 32],
420 payload: Vec<u8, 64>,
421}
422
423impl Debug for SignedPayload {
424 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
425 write!(f, "SignedPayload(")?;
426 for b in &self.ed25519 {
427 write!(f, "{b:02x}")?;
428 }
429 write!(f, ", ")?;
430 for b in &self.payload {
431 write!(f, "{b:02x}")?;
432 }
433 write!(f, ")")
434 }
435}
436
437impl SignedPayload {
438 pub(crate) const MAX_PAYLOAD_LEN: usize = 32 + 4 + 64;
440 pub(crate) const MAX_BINARY_LEN: usize = binary_len(Self::MAX_PAYLOAD_LEN);
441 pub const MAX_ENCODED_LEN: usize = encode_len(Self::MAX_BINARY_LEN);
442 const MIN_INNER_PAYLOAD_LEN: usize = 1;
443 const MAX_INNER_PAYLOAD_LEN: usize = 64;
444 const MAX_INNER_PAYLOAD_LEN_U32: u32 = 64;
445 const _ASSERTS: () = {
446 assert!(Self::MAX_PAYLOAD_LEN == 100);
447 assert!(Self::MAX_BINARY_LEN == 103);
448 assert!(Self::MAX_ENCODED_LEN == 165);
449 assert!(Self::MAX_INNER_PAYLOAD_LEN as u32 == Self::MAX_INNER_PAYLOAD_LEN_U32);
450 assert!(Self::MAX_INNER_PAYLOAD_LEN_U32 as usize == Self::MAX_INNER_PAYLOAD_LEN);
451 };
452
453 pub fn new(ed25519: [u8; 32], payload: &[u8]) -> Result<Self, DecodeError> {
459 if !(Self::MIN_INNER_PAYLOAD_LEN..=Self::MAX_INNER_PAYLOAD_LEN).contains(&payload.len()) {
460 return Err(DecodeError::InvalidPayloadLength);
461 }
462 let mut p = Vec::new();
463 p.extend_from_slice(payload)
464 .map_err(|_| DecodeError::InvalidPayloadLength)?;
465 Ok(Self {
466 ed25519,
467 payload: p,
468 })
469 }
470
471 pub fn ed25519(&self) -> &[u8; 32] {
473 &self.ed25519
474 }
475
476 pub fn payload(&self) -> &[u8] {
478 &self.payload
479 }
480
481 pub fn to_string(&self) -> String<{ Self::MAX_ENCODED_LEN }> {
483 let inner_payload_len = self.payload.len();
484 let payload_len = 32 + 4 + inner_payload_len + (4 - inner_payload_len % 4) % 4;
485
486 let inner_payload_len_u32: u32 = inner_payload_len as u32;
487
488 let mut payload = [0u8; Self::MAX_PAYLOAD_LEN];
490 payload[..32].copy_from_slice(&self.ed25519);
491 payload[32..32 + 4].copy_from_slice(&(inner_payload_len_u32).to_be_bytes());
492 payload[32 + 4..32 + 4 + inner_payload_len].copy_from_slice(&self.payload);
493
494 encode::<{ Self::MAX_PAYLOAD_LEN }, { Self::MAX_BINARY_LEN }, { Self::MAX_ENCODED_LEN }>(
495 version::SIGNED_PAYLOAD_ED25519,
496 &payload[..payload_len],
497 )
498 }
499
500 pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
508 const MIN_LENGTH: usize = 32 + 4 + 4;
513 const MAX_LENGTH: usize = 32 + 4 + SignedPayload::MAX_INNER_PAYLOAD_LEN;
514 let payload_len = payload.len();
515 if !(MIN_LENGTH..=MAX_LENGTH).contains(&payload_len) {
516 return Err(DecodeError::InvalidPayloadLength);
517 }
518
519 let mut offset = 0;
521 let ed25519: [u8; 32] = payload
522 .get(offset..offset + 32)
523 .ok_or(DecodeError::InvalidPayloadLength)?
524 .try_into()
525 .map_err(|_| DecodeError::InvalidPayloadLength)?;
526 offset += 32;
527
528 let inner_payload_len = u32::from_be_bytes(
530 payload
531 .get(offset..offset + 4)
532 .ok_or(DecodeError::InvalidPayloadLength)?
533 .try_into()
534 .map_err(|_| DecodeError::InvalidPayloadLength)?,
535 );
536 offset += 4;
537
538 if inner_payload_len > Self::MAX_INNER_PAYLOAD_LEN_U32 {
540 return Err(DecodeError::InvalidPayloadLength);
541 }
542
543 let inner_payload = payload
545 .get(offset..offset + inner_payload_len as usize)
546 .ok_or(DecodeError::InvalidPayloadLength)?;
547 offset += inner_payload_len as usize;
548
549 let padding_len = (4 - inner_payload_len % 4) % 4;
551
552 let padding = payload
554 .get(offset..offset + padding_len as usize)
555 .ok_or(DecodeError::InvalidPayloadLength)?;
556 offset += padding_len as usize;
557
558 if padding.iter().any(|b| *b != 0) {
560 return Err(DecodeError::InvalidPadding);
561 }
562
563 if offset != payload_len {
565 return Err(DecodeError::InvalidPayloadLength);
566 }
567
568 Self::new(ed25519, inner_payload)
569 }
570
571 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
572 Self::from_slice(s.as_bytes())
573 }
574
575 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
576 let (ver, payload) = decode::<{ Self::MAX_PAYLOAD_LEN }, { Self::MAX_BINARY_LEN }>(s)?;
577 match ver {
578 version::SIGNED_PAYLOAD_ED25519 => Self::from_payload(&payload),
579 _ => Err(DecodeError::UnsupportedVersion),
580 }
581 }
582}
583
584impl Display for SignedPayload {
585 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
586 write!(f, "{}", self.to_string())
587 }
588}
589
590impl FromStr for SignedPayload {
591 type Err = DecodeError;
592
593 fn from_str(s: &str) -> Result<Self, Self::Err> {
594 SignedPayload::from_string(s)
595 }
596}
597
598#[cfg(feature = "serde-decoded")]
599mod signed_payload_decoded_serde_impl {
600 use super::SignedPayload;
601 use crate::decoded_json_format::Decoded;
602 use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
603 use serde_with::serde_as;
604
605 #[serde_as]
606 #[derive(Serialize)]
607 struct DecodedBorrowed<'a> {
608 #[serde_as(as = "serde_with::hex::Hex")]
609 ed25519: &'a [u8; 32],
610 #[serde_as(as = "serde_with::hex::Hex")]
611 payload: &'a [u8],
612 }
613
614 #[serde_as]
615 #[derive(Deserialize)]
616 struct DecodedOwned {
617 #[serde_as(as = "serde_with::hex::Hex")]
618 ed25519: [u8; 32],
619 #[serde_as(as = "serde_with::hex::Hex")]
620 payload: alloc::vec::Vec<u8>,
621 }
622
623 impl Serialize for Decoded<&SignedPayload> {
624 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
625 let Self(sp) = self;
626 DecodedBorrowed {
627 ed25519: sp.ed25519(),
628 payload: sp.payload(),
629 }
630 .serialize(serializer)
631 }
632 }
633
634 impl<'de> Deserialize<'de> for Decoded<SignedPayload> {
635 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
636 let DecodedOwned { ed25519, payload } = DecodedOwned::deserialize(deserializer)?;
637 let sp = SignedPayload::new(ed25519, &payload)
638 .map_err(|e| de::Error::custom(format_args!("invalid signed payload: {e}")))?;
639 Ok(Decoded(sp))
640 }
641 }
642}
643
644#[cfg(test)]
645mod tests {
646 use super::PrivateKey;
647 use heapless::String;
648 use zeroize::Zeroizing;
649
650 #[test]
653 fn test_private_key_write_string_matches_to_string() {
654 let key = PrivateKey([
655 0x69, 0xa8, 0xc4, 0xcb, 0xb9, 0xf6, 0x4e, 0x8a, 0x07, 0x98, 0xf6, 0xe1, 0xac, 0x65,
656 0xd0, 0x6c, 0x31, 0x62, 0x92, 0x90, 0x56, 0xbc, 0xf4, 0xcd, 0xb7, 0xd3, 0x73, 0x8d,
657 0x18, 0x55, 0xf3, 0x63,
658 ]);
659 let mut buf: Zeroizing<String<{ PrivateKey::ENCODED_LEN }>> = Zeroizing::new(String::new());
660 key.as_unredacted().write_string(&mut buf);
661 assert_eq!(
662 buf.as_str(),
663 "SBU2RRGLXH3E5CQHTD3ODLDF2BWDCYUSSBLLZ5GNW7JXHDIYKXZWHOKR"
664 );
665 assert_eq!(buf.as_str(), key.as_unredacted().to_string().as_str());
666 }
667}