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`, `W`) 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`], [`MuxedContract`]) 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//! | `W`    | [`Strkey::MuxedContract`] / [`MuxedContract`]                          |            40 |
44//!
45//! # Examples
46//!
47//! Parse any strkey when the kind isn't known up front:
48//!
49//! ```
50//! use stellar_strkey::Strkey;
51//!
52//! let s = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
53//! let strkey: Strkey = s.parse().unwrap();
54//! assert!(matches!(strkey, Strkey::PublicKeyEd25519(_)));
55//! ```
56//!
57//! Parse a specific kind and reject anything else:
58//!
59//! ```
60//! use stellar_strkey::Contract;
61//!
62//! let s = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4";
63//! let contract: Contract = s.parse().unwrap();
64//! assert_eq!(contract.0, [0u8; 32]);
65//! ```
66//!
67//! Construct a strkey from raw bytes and render it:
68//!
69//! ```
70//! use stellar_strkey::ed25519::PublicKey;
71//!
72//! let key = PublicKey([0u8; 32]);
73//! assert_eq!(
74//!     key.to_string().as_str(),
75//!     "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF",
76//! );
77//! ```
78//!
79//! # `no_std`
80//!
81//! With default features the crate is `no_std` and does not depend on
82//! `alloc`. Encoding uses fixed-capacity buffers from the `heapless` crate,
83//! so each kind's `to_string` returns a `heapless::String` sized to the
84//! maximum length for that kind.
85//!
86//! # Cargo features
87//!
88//! - `serde` — derives [`Serialize`]/[`Deserialize`] that round-trip strkeys
89//!   as their textual form. [`ed25519::PrivateKey`] is `Deserialize` but
90//!   not directly `Serialize`; wrap in [`Unredacted`] to serialize.
91//! - `serde-decoded` — adds a `Decoded<T>` wrapper that serializes a strkey
92//!   as a structured JSON object with hex-encoded byte fields, which is
93//!   useful for tooling that wants to inspect the underlying bytes. Requires
94//!   `alloc` and implies `serde`.
95//! - `cli` — builds the `stellar-strkey` binary for encoding and decoding
96//!   strkeys from the command line. Requires `std` (disables `no_std` for
97//!   the crate). Not intended for enabling with the library.
98//!
99//! [Stellar strkeys]: https://developers.stellar.org/docs/learn/glossary#strkey
100//! [SEP-23]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0023.md
101//! [`Serialize`]: https://docs.rs/serde/latest/serde/trait.Serialize.html
102//! [`Deserialize`]: https://docs.rs/serde/latest/serde/trait.Deserialize.html
103
104#![cfg_attr(not(feature = "cli"), no_std)]
105
106#[cfg(feature = "serde-decoded")]
107extern crate alloc;
108
109#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
110pub struct Version<'a> {
111    pub pkg: &'a str,
112    pub rev: &'a str,
113}
114pub const VERSION: Version = Version {
115    pkg: env!("CARGO_PKG_VERSION"),
116    rev: env!("GIT_REVISION"),
117};
118
119#[doc(hidden)]
120pub mod convert;
121mod crc;
122pub mod ed25519;
123mod error;
124mod strkey;
125mod typ;
126mod unredacted;
127mod version;
128
129pub use error::*;
130pub use strkey::*;
131pub use unredacted::Unredacted;
132
133#[cfg(feature = "serde-decoded")]
134pub mod decoded_json_format;
135#[cfg(feature = "serde-decoded")]
136pub use decoded_json_format::Decoded;
137
138#[cfg(feature = "cli")]
139pub mod cli;