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;