stellar/stellar-core · Archived

subsystem-summary-of-crypto

read this skill for a token-efficient summary of the crypto subsystem

First seen Apr 29, 2026

Installation

$ npx skills add stellar/stellar-core --skill subsystem-summary-of-crypto

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Also in this package

Other skills from stellar/stellar-core · top by installs.

npx skills add stellar/stellar-core

Browse all from stellar/stellar-core

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 3.3K
License LICENSE-APACHE.txt
Default branch master
Open issues 257
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 15,138 B
  • docs SUMMARY.md 104 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 3 installs

SKILL.md

Crypto Subsystem Technical Summary

Overview

The src/crypto/ subsystem provides all cryptographic primitives for stellar-core: hashing (SHA-256, BLAKE2b, SipHash), Ed25519 key management and signatures, Curve25519 ECDH key agreement, StrKey encoding/decoding, hex utilities, and random number generation. It is built on top of libsodium and uses xdrpp for serialization. There are no background threads or event loops in this subsystem; it is a stateless utility layer with one notable piece of process-wide shared state: the signature verification cache.


Key Classes and Data Structures

ByteSlice (ByteSlice.h)

A lightweight, non-owning, read-only view over contiguous byte data. Acts as a universal adaptor for passing byte containers into crypto functions. Implicitly constructs from xdr::opaquearray<N>, xdr::msgptr, std::vector<uint8t>, std::string, rust::Vec<uint8t>, RustBuf, char const, and raw (void, size_t). Provides data(), size(), begin(), end(), operator[] (bounds-checked), and empty().

CryptoError (CryptoError.h)

Simple exception class inheriting std::runtime_error. Thrown by all crypto functions on failure (e.g., libsodium errors, invalid inputs).

SecretKey (SecretKey.h / SecretKey.cpp)

Represents an Ed25519 signing keypair (secret key + derived public key).

Internal state:

  • mKeyType (PublicKeyType) — always PUBLICKEYTYPE_ED25519
  • mSecretKey (uint512 / 64-byte opaque array) — the libsodium combined secret key
  • mPublicKey (PublicKey) — the corresponding public key (XDR type)
  • Nested Seed struct holds a 32-byte seed; its destructor zeroes memory.

Key methods:

  • getPublicKey() — returns const ref to mPublicKey
  • getStrKeySeed() — returns StrKey-encoded seed as SecretValue
  • getStrKeyPublic() — returns StrKey-encoded public key as std::string
  • isZero() — true if seed is all-zero
  • sign(ByteSlice) — produces a 64-byte Ed25519 detached signature via cryptosigndetached
  • random() — generates a cryptographically random keypair via cryptosignkeypair
  • fromSeed(ByteSlice) — derives keypair from a 32-byte seed via cryptosignseed_keypair
  • fromStrKeySeed(string) — decodes a StrKey seed string, then derives keypair

Destructor zeroes mSecretKey memory to prevent key leakage.

PublicKey (XDR-defined, utilities in SecretKey.h/cpp)

The XDR union type for public keys. The crypto subsystem provides KeyFunctions<PublicKey> specialization and the PubKeyUtils namespace.

PubKeyUtils namespace (SecretKey.h / SecretKey.cpp)

Signature verification and public key utilities.

Key functions:

  • verifySig(PublicKey, Signature, ByteSlice) → VerifySigResult — Verifies an Ed25519 signature. Uses a process-wide RandomEvictionCache<Hash, bool> (capacity 250,000 entries) protected by gVerifySigCacheMutex. Returns both the validity result and whether it was a cache hit/miss. Supports switching between libsodium (cryptosignverifydetached) and Rust ed25519-dalek (rustbridge::verifyed25519signature_dalek) at the protocol 24 boundary.
  • clearVerifySigCache() — clears the global cache
  • seedVerifySigCache(unsigned int) — seeds the cache's random eviction PRNG
  • flushVerifySigCacheCounts(hits, misses) — atomically reads and resets cache hit/miss counters
  • enableRustDalekVerify() — one-way flag to switch signature verification to Rust ed25519-dalek
  • random() — generates a random (non-signing-capable) public key

VerifySigResult (SecretKey.h)

Struct with two fields: bool valid (signature validity) and VerifySigCacheLookupResult cacheResult (enum: MISS, HIT, NO_LOOKUP).


Hashing Modules

SHA-256 (SHA.h / SHA.cpp)

Free functions:

  • sha256(ByteSlice) → uint256 — one-shot SHA-256 hash via cryptohashsha256
  • subSha256(ByteSlice seed, uint64_t counter) → Hash — SHA-256 of seed concatenated with XDR-serialized counter; used for sub-seeding per-transaction PRNGs in Soroban
  • hmacSha256(HmacSha256Key, ByteSlice) → HmacSha256Mac — HMAC-SHA-256 via cryptoauthhmacsha256
  • hmacSha256Verify(HmacSha256Mac, HmacSha256Key, ByteSlice) → bool — constant-time HMAC verification via cryptoauthhmacsha256_verify
  • hkdfExtract(ByteSlice) → HmacSha256Key — unsalted HKDF-extract: HMAC(<zero_key>, bytes)
  • hkdfExpand(HmacSha256Key, ByteSlice) → HmacSha256Key — single-step HKDF-expand: HMAC(key, bytes||0x01)

SHA256 class — incremental (streaming) SHA-256 hasher:

  • reset() — reinitializes state
  • add(ByteSlice) — feeds data
  • finish() → uint256 — finalizes and returns hash (single use; throws if called again)

XDRSHA256 struct — CRTP subclass of XDRHasher<XDRSHA256> wrapping SHA256. Used by xdrSha256<T>(t) template to hash any XDR object without intermediate serialization buffer.

BLAKE2b (BLAKE2.h / BLAKE2.cpp)

Free function:

  • blake2(ByteSlice) → uint256 — one-shot BLAKE2b (256-bit output) via crypto_generichash

BLAKE2 class — incremental BLAKE2b hasher (same API pattern as SHA256):

  • reset(), add(ByteSlice), finish() → uint256

XDRBLAKE2 struct — CRTP subclass of XDRHasher<XDRBLAKE2> wrapping BLAKE2. Used by xdrBlake2<T>(t) template.

BLAKE2 is used internally in the signature verification cache key computation (verifySigCacheKey hashes public key + signature + message via BLAKE2).

ShortHash / SipHash (ShortHash.h / ShortHash.cpp)

Fast, randomized, non-cryptographic hash for in-memory data structures (hash maps, etc.).

shortHash namespace:

  • initialize() — generates a random per-process SipHash key via cryptoshorthashkeygen; must be called once at startup
  • getShortHashInitKey() → array<unsigned char, 16> — returns current key (used for child process inheritance)
  • computeHash(ByteSlice) → uint64t — SipHash-2-4 via cryptoshorthash, mutex-protected to set gHaveHashed flag
  • xdrComputeHash<T>(t) → uint64_t — hashes any XDR object without intermediate buffer, using XDRShortHasher

XDRShortHasher struct — CRTP subclass of XDRHasher<XDRShortHasher> wrapping SipHash24 state. Initialized with the process-wide key.

Thread safety: All access to the global key gKey is mutex-protected via gKeyMutex.

XDRHasher (XDRHasher.h)

CRTP base class template XDRHasher<Derived> providing an xdrpp-compatible archiver that feeds XDR-serialized bytes to a hash function without allocating an intermediate serialization buffer.

Mechanism:

  • Maintains a 256-byte internal buffer (mBuf) for batching small writes
  • queueOrHash(bytes, size) — buffers small writes; flushes and calls Derived::hashBytes() for larger ones
  • flush() — sends any buffered bytes to the derived hasher
  • operator() overloads handle XDR scalars (32/64-bit with endian swap), byte arrays (with XDR padding), and composite types (delegating to xdr::xdr_traits<T>::save)

Three concrete derivations: XDRSHA256, XDRBLAKE2, XDRShortHasher.


Key Encoding / Decoding Modules

StrKey (StrKey.h / StrKey.cpp)

Implements Stellar's base32-encoded key format with version byte and CRC-16 checksum.

strKey namespace:

  • StrKeyVersionByte enum — version bytes for different key types: STRKEYPUBKEYED25519 ('G'), STRKEYSEEDED25519 ('S'), STRKEYPREAUTHTX ('T'), STRKEYHASHX ('X'), STRKEYSIGNEDPAYLOADED25519 ('P'), STRKEYMUXEDACCOUNTED25519 ('M'), STRKEYCONTRACT ('C')
  • toStrKey(ver, ByteSlice) → SecretValue — encodes: base32(version_byte || payload || crc16)
  • fromStrKey(string, &ver, &decoded) → bool — decodes and validates CRC-16 checksum
  • getStrKeySize(dataSize) → size_t — computes encoded string length for a given payload size

KeyUtils (KeyUtils.h / KeyUtils.cpp)

Template-based key conversion utilities using the KeyFunctions<T> trait.

KeyFunctions<T> trait — specialization point for each key type, providing:

  • getKeyTypeName(), getKeyVersionIsSupported(), getKeyVersionIsVariableLength()
  • toKeyType() / toKeyVersion() — convert between StrKeyVersionByte and the key type enum
  • getEd25519Value() / getKeyValue() / setKeyValue() — access raw key bytes

Specializations provided: KeyFunctions<PublicKey> (in SecretKey.h/cpp), KeyFunctions<SignerKey> (in SignerKey.h/cpp).

KeyUtils namespace template functions:

  • toStrKey<T>(key) — converts any key type to StrKey string
  • toShortString<T>(key) — first 5 characters of StrKey (for logging)
  • fromStrKey<T>(string) — parses StrKey string into a typed key
  • getKeyVersionSize(StrKeyVersionByte) — returns expected raw key size for a version byte
  • canConvert<T, F>(fromKey) — checks if key type conversion is possible
  • convertKey<T, F>(fromKey) — converts between key types sharing the same Ed25519 value

Hex (Hex.h / Hex.cpp)

Hex encoding/decoding utilities using libsodium.

  • binToHex(ByteSlice) → string — hex-encodes bytes
  • hexAbbrev(ByteSlice) → string — returns first 6 hex characters (3 bytes) for logging
  • hexToBin(string) → vector<uint8_t> — hex-decodes a string
  • hexToBin256(string) → uint256 — hex-decodes exactly 32 bytes, throws otherwise

Signer Key Utilities

SignerKey (SignerKey.h / SignerKey.cpp)

Provides KeyFunctions<SignerKey> specialization supporting four signer key types:

  • SIGNERKEYTYPE_ED25519 — standard Ed25519 public key
  • SIGNERKEYTYPEPREAUTH_TX — pre-authorized transaction hash
  • SIGNERKEYTYPEHASHX — hash(x) preimage signer
  • SIGNERKEYTYPEED25519SIGNED_PAYLOAD — Ed25519 key with attached payload (variable length, up to 96 bytes)

SignerKeyUtils (SignerKeyUtils.h / SignerKeyUtils.cpp)

Factory functions for creating SignerKey objects:

  • preAuthTxKey(TransactionFrame) — creates a pre-auth signer key from a transaction's contents hash
  • preAuthTxKey(FeeBumpTransactionFrame) — same for fee-bump transactions
  • hashXKey(ByteSlice) — creates a hash-x signer key by SHA-256 hashing the input
  • ed25519PayloadKey(uint256, opaque_vec<64>) — creates an ed25519-signed-payload signer key

Curve25519 / ECDH (Curve25519.h / Curve25519.cpp)

Provides Curve25519 Diffie-Hellman key agreement for the P2P overlay authentication system (PeerAuth). These keys are distinct from Ed25519 signing keys and are generated per-session.

Key functions:

  • curve25519RandomSecret() → Curve25519Secret — generates random 32-byte scalar via randombytes_buf
  • curve25519DerivePublic(Curve25519Secret) → Curve25519Public — derives public point via cryptoscalarmultbase
  • clearCurve25519Keys(pub, sec) — zeroes both keys via sodium_memzero
  • curve25519DeriveSharedKey(localSecret, localPublic, remotePublic, localFirst) → HmacSha256Key — performs ECDH (cryptoscalarmult), concatenates sharedsecret || publicA || publicB (ordered by localFirst), then applies hkdfExtract
  • curve25519Encrypt<N>(remotePublic, ByteSlice) → opaquevec<N> — sealed box encryption via cryptobox_seal
  • curve25519Decrypt(localSecret, localPublic, ByteSlice) → opaquevec<> — sealed box decryption via cryptoboxsealopen

Random Number Generation (Random.h / Random.cpp)

  • randomBytes(sizet length) → vector<uint8t> — generates cryptographically secure random bytes via libsodium's randombytes_buf. In fuzzing builds, uses a deterministic PRNG instead.

Logging Utilities

StrKeyUtils::logKey(ostream, string) (SecretKey.cpp)

Attempts to interpret a key string in all known formats (public key StrKey, seed StrKey, raw hex) and logs all possible interpretations. Used for diagnostic/debugging output.

HashUtils namespace (SecretKey.h / SecretKey.cpp)

  • random() → Hash — generates a random 32-byte hash via randombytes_buf

Thread Safety and Shared State

The crypto subsystem is mostly stateless/pure-functional. The two pieces of process-wide shared mutable state are:

  1. Signature verification cache (gVerifySigCache, gVerifyCacheHit, gVerifyCacheMiss, gUseRustDalekVerify) — protected by gVerifySigCacheMutex. The cache is a RandomEvictionCache<Hash, bool> of 250K entries. Cache keys are BLAKE2 hashes of (public_key || signature || message). Access is serialized by mutex, but individual verify operations are performed outside the lock.
  1. ShortHash global key (gKey, gHaveHashed) — protected by gKeyMutex. Initialized once at startup via shortHash::initialize().

There are no background threads, event loops, or async tasks in the crypto subsystem.


Key Data Flows

Signature Creation

SecretKey::sign(message) → cryptosigndetached(message, secret_key) → 64-byte Signature

Signature Verification

PubKeyUtils::verifySig(pubkey, sig, message) → compute BLAKE2 cache key → lock mutex → check gVerifySigCache → if miss, unlock, verify via libsodium or Rust dalek (depending on gUseRustDalekVerify flag) → lock mutex → insert result into cache → return VerifySigResult

StrKey Encoding

Raw key bytes → strKey::toStrKey(version_byte, bytes) → prepend version byte, append CRC-16 → base32-encode → StrKey string

StrKey Decoding

StrKey string → strKey::fromStrKey() → base32-decode → verify CRC-16 → extract version byte and payload → KeyUtils::fromStrKey<T>() → construct typed key

ECDH Shared Key Derivation (P2P overlay)

curve25519RandomSecret() → curve25519DerivePublic() → exchange public keys → curve25519DeriveSharedKey() → crypto_scalarmult (ECDH) → concatenate with ordered public keys → hkdfExtract() → HmacSha256Key

XDR Hashing (zero-copy)

Any XDR object → xdrSha256<T>(t) / xdrBlake2<T>(t) / shortHash::xdrComputeHash<T>(t) → xdr::archive(hasher, t) → XDRHasher::operator() dispatches by XDR type → batched hashBytes() calls → finalize


Ownership Relationships

  • SecretKey owns its mSecretKey (64-byte secret), mPublicKey (XDR PublicKey), and mKeyType
  • ByteSlice borrows (non-owning view) from any byte container
  • SHA256, BLAKE2 classes own their respective libsodium hash states
  • XDRHasher<D> owns a 256-byte internal buffer; derived types own their hash state
  • XDRShortHasher owns a SipHash24 state initialized from the global key
  • The global signature cache (gVerifySigCache) is a process-wide singleton RandomEvictionCache<Hash, bool>
  • The global short-hash key (gKey) is a process-wide singleton byte array
  • Curve25519Secret / Curve25519Public are value types (XDR opaque_array<32> wrappers)
  • SignerKey is an XDR union owned by its creator; SignerKeyUtils functions are pure factories