Skip to main content

stellar_strkey/
lib.rs

1//! Encode and decode [Stellar strkeys] as defined by [SEP-23].
2//!
3//! Strkeys are the human-readable textual representation of identifiers used
4//! across the Stellar network — account IDs, signing keys, contract IDs,
5//! liquidity pool IDs, and others. Each strkey begins with a single ASCII
6//! letter that identifies its kind (`G`, `S`, `M`, `T`, `X`, `P`, `C`, `L`,
7//! `B`) and is encoded as base32 without padding. The binary form is a
8//! one-byte version, the type's payload, and a two-byte CRC16-XMODEM
9//! checksum, ensuring that mistyped strkeys are detected before they are
10//! used.
11//!
12//! This crate provides:
13//!
14//! - The [`Strkey`] enum, which can hold and round-trip any strkey kind
15//!   other than `PrivateKeyEd25519` (`S…`); private-key strkeys are
16//!   handled directly via [`ed25519::PrivateKey`], with rendering gated
17//!   behind [`Unredacted`].
18//! - Per-kind types in this module ([`PreAuthTx`], [`HashX`], [`Contract`],
19//!   [`LiquidityPool`], [`ClaimableBalance`]) and in [`ed25519`]
20//!   ([`ed25519::PublicKey`], [`ed25519::PrivateKey`],
21//!   [`ed25519::MuxedAccount`], [`ed25519::SignedPayload`]) for callers that
22//!   know the kind in advance.
23//! - [`Display`](core::fmt::Display) and [`FromStr`](core::str::FromStr)
24//!   implementations for every kind, plus inherent `to_string` /
25//!   `from_string` / `from_slice` methods. [`ed25519::PrivateKey`] is the
26//!   exception: it does not implement `Display` or inherent `to_string`
27//!   directly — wrap it in [`Unredacted`] (`pk.as_unredacted()`) to render
28//!   the encoded strkey form.
29//!
30//! # Strkey kinds
31//!
32//! | Prefix | Kind                                                                  | Payload bytes |
33//! |--------|-----------------------------------------------------------------------|---------------|
34//! | `G`    | [`Strkey::PublicKeyEd25519`] / [`ed25519::PublicKey`]                  |            32 |
35//! | `S`    | [`ed25519::PrivateKey`] only (omitted from [`Strkey`])                 |            32 |
36//! | `M`    | [`Strkey::MuxedAccountEd25519`] / [`ed25519::MuxedAccount`]            |            40 |
37//! | `T`    | [`Strkey::PreAuthTx`] / [`PreAuthTx`]                                  |            32 |
38//! | `X`    | [`Strkey::HashX`] / [`HashX`]                                          |            32 |
39//! | `P`    | [`Strkey::SignedPayloadEd25519`] / [`ed25519::SignedPayload`]          |        40–100 |
40//! | `C`    | [`Strkey::Contract`] / [`Contract`]                                    |            32 |
41//! | `L`    | [`Strkey::LiquidityPool`] / [`LiquidityPool`]                          |            32 |
42//! | `B`    | [`Strkey::ClaimableBalance`] / [`ClaimableBalance`]                    |            33 |
43//!
44//! # Examples
45//!
46//! Parse any strkey when the kind isn't known up front:
47//!
48//! ```
49//! use stellar_strkey::Strkey;
50//!
51//! let s = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
52//! let strkey: Strkey = s.parse().unwrap();
53//! assert!(matches!(strkey, Strkey::PublicKeyEd25519(_)));
54//! ```
55//!
56//! Parse a specific kind and reject anything else:
57//!
58//! ```
59//! use stellar_strkey::Contract;
60//!
61//! let s = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4";
62//! let contract: Contract = s.parse().unwrap();
63//! assert_eq!(contract.0, [0u8; 32]);
64//! ```
65//!
66//! Construct a strkey from raw bytes and render it:
67//!
68//! ```
69//! use stellar_strkey::ed25519::PublicKey;
70//!
71//! let key = PublicKey([0u8; 32]);
72//! assert_eq!(
73//!     key.to_string().as_str(),
74//!     "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF",
75//! );
76//! ```
77//!
78//! # `no_std`
79//!
80//! With default features the crate is `no_std` and does not depend on
81//! `alloc`. Encoding uses fixed-capacity buffers from the `heapless` crate,
82//! so each kind's `to_string` returns a `heapless::String` sized to the
83//! maximum length for that kind.
84//!
85//! # Cargo features
86//!
87//! - `serde` — derives [`Serialize`]/[`Deserialize`] that round-trip strkeys
88//!   as their textual form. [`ed25519::PrivateKey`] is `Deserialize` but
89//!   not directly `Serialize`; wrap in [`Unredacted`] to serialize.
90//! - `serde-decoded` — adds a `Decoded<T>` wrapper that serializes a strkey
91//!   as a structured JSON object with hex-encoded byte fields, which is
92//!   useful for tooling that wants to inspect the underlying bytes. Requires
93//!   `alloc` and implies `serde`.
94//! - `cli` — builds the `stellar-strkey` binary for encoding and decoding
95//!   strkeys from the command line. Requires `std` (disables `no_std` for
96//!   the crate). Not intended for enabling with the library.
97//!
98//! [Stellar strkeys]: https://developers.stellar.org/docs/learn/glossary#strkey
99//! [SEP-23]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
100//! [`Serialize`]: https://docs.rs/serde/latest/serde/trait.Serialize.html
101//! [`Deserialize`]: https://docs.rs/serde/latest/serde/trait.Deserialize.html
102
103#![cfg_attr(not(feature = "cli"), no_std)]
104
105#[cfg(feature = "serde-decoded")]
106extern crate alloc;
107
108#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
109pub struct Version<'a> {
110    pub pkg: &'a str,
111    pub rev: &'a str,
112}
113pub const VERSION: Version = Version {
114    pkg: env!("CARGO_PKG_VERSION"),
115    rev: env!("GIT_REVISION"),
116};
117
118#[doc(hidden)]
119pub mod convert;
120mod crc;
121pub mod ed25519;
122mod error;
123mod strkey;
124mod typ;
125mod unredacted;
126mod version;
127
128pub use error::*;
129pub use strkey::*;
130pub use unredacted::Unredacted;
131
132#[cfg(feature = "serde-decoded")]
133pub mod decoded_json_format;
134#[cfg(feature = "serde-decoded")]
135pub use decoded_json_format::Decoded;
136
137#[cfg(feature = "cli")]
138pub mod cli;