The Lifecycle of a Cryptographic Key

← Back to Cryptography I: Blockchain Security and Cryptographic Foundations

Introduction

Let's follow the lifecycle of a cryptographic key in rippled, from its creation as random noise to its role as the foundation of an account's identity. This journey touches every aspect of rippled's cryptographic system and shows how the pieces fit together.

Understanding this lifecycle is crucial because keys are the foundation of everything in XRPL. Every account, every transaction, every validator message—all depend on the proper generation, handling, and use of cryptographic keys.

The Journey Begins: Birth Through Randomness

Everything begins with randomness. Not the pseudo-randomness of Math.random() or std::rand(), but true cryptographic randomness—numbers that are fundamentally unpredictable.

Why Randomness Matters

If an attacker can predict your random numbers, they can predict your keys. If they can predict your keys, they own your account. The stakes couldn't be higher.

// ❌ WRONG - Predictable and insecure
void generateWeakKey() {
    std::srand(std::time(nullptr));  // Predictable seed!
    std::uint8_t buf[32];
    for (auto& byte : buf)
        byte = std::rand() % 256;  // NOT cryptographically secure
}

// ✅ CORRECT - Cryptographically secure
SecretKey generateStrongKey() {
    std::uint8_t buf[32];
    beast::rngfill(buf, sizeof(buf), crypto_prng());  // CSPRNG
    SecretKey sk{Slice{buf, sizeof(buf)}};
    secure_erase(buf, sizeof(buf));  // Clean up
    return sk;
}

The Birth of a Secret Key

In rippled, randomness comes from the crypto_prng() function, which wraps OpenSSL's RAND_bytes:

What happens here:

  1. Allocate buffer: A 32-byte buffer is created on the stack

  2. Fill with randomness: crypto_prng() fills it with cryptographically secure random bytes from OpenSSL

  3. Create SecretKey: The buffer is wrapped in a SecretKey object

  4. Secure cleanup: The temporary buffer is securely erased to prevent key material from lingering in memory

Where Randomness Comes From

When you call crypto_prng(), OpenSSL pulls entropy from multiple sources:

This multi-source approach ensures that even if one entropy source is weak, others provide backup security.

Growth: From Secret to Public

With a secret key in hand, we need to derive its public key—the identity we can share with the world. This derivation is one of the beautiful ideas in modern cryptography: a mathematical function that's easy to compute in one direction but effectively impossible to reverse.

The One-Way Function

This asymmetry is what makes public-key cryptography possible.

Two Algorithms, Two Approaches

XRPL supports two cryptographic algorithms, each with its own derivation process:

secp256k1: Elliptic Curve Point Multiplication

How it works:

  • Elliptic curve has a special "generator" point G

  • Public key = Secret key × G (point multiplication on the curve)

  • Result is a point with X and Y coordinates

  • Compressed format stores X coordinate + one bit for Y (33 bytes total)

    • Prefix byte: 0x02 or 0x03 (indicates Y parity)

    • X coordinate: 32 bytes

Why it's secure:

  • Computing Public = Secret × G is fast

  • Computing Secret from Public requires solving the discrete logarithm problem

  • No known efficient algorithm exists for this problem

ed25519: Curve25519 Operations

How it works:

  • Uses Ed25519 curve operations (optimized variant of Curve25519)

  • Derives public key through curve arithmetic

  • Adds 0xED prefix byte to identify key type

  • Total 33 bytes (1 prefix + 32 public key)

Why it's secure:

  • Based on different curve with different security proofs

  • Specifically designed for signing (not encryption)

  • More resistant to implementation errors

The Beauty of One-Way Functions

The public key can be:

  • Posted on websites

  • Included in transactions

  • Sent to strangers

  • Stored in public databases

No matter who has it or what they do with it, they can't derive your secret key. Your private identity remains private.

Alternative Path: Deterministic Generation

Sometimes we don't want pure randomness. Sometimes we want to be able to recreate the exact same key pair from a remembered or stored value. This is where seed-based deterministic key generation comes in.

Why Deterministic Keys?

Problem with pure randomness:

Solution with seeds:

How Seeds Work

A seed is a small piece of data—typically 16 bytes—that serves as the "master secret" for an entire family of keys:

For ed25519: Simple and Direct

Simple, deterministic, and secure. Same seed always produces same key.

For secp256k1: Handling Edge Cases

Why the loop? Not all 32-byte values are valid secret keys for secp256k1. The value must be less than the curve's "order" (a large prime number). If the hash result is too large, increment a counter and try again.

The odds of needing more than one attempt are vanishingly small (roughly 1 in 2^128), but the code handles it correctly.

The Generator Pattern

The Generator class enables creating multiple independent keys from one seed:

Each ordinal produces a cryptographically independent key pair. This enables powerful features like:

  • Hierarchical wallets: One seed, many accounts

  • Key rotation: Generate new keys without remembering multiple seeds

  • Backup simplicity: One seed backs up everything

From Key to Identity: Account IDs

A public key isn't an address. To get the human-readable XRPL address (starting with 'r'), we need one more transformation:

The RIPESHA Double Hash

Why two hash functions?

  1. Compactness: 20 bytes instead of 33 bytes

  2. Defense in depth: If SHA-256 is broken, RIPEMD-160 provides protection; if RIPEMD-160 is broken, SHA-256 does

  3. Compatibility: Same scheme used by other blockchain systems

Why hash at all?

  • Shorter addresses are easier to use

  • Provides a level of indirection (can't derive public key from address)

  • Quantum-resistant: even if quantum computers break elliptic curve crypto, they can't derive the public key from the address alone

The Complete Lifecycle

Let's trace a key from birth to address:

Each step is irreversible:

  • Can't derive secret from public

  • Can't derive public from account ID

  • Can't derive account ID from address (but can decode)

Lifecycle Management: RAII and Secure Cleanup

The SecretKey class demonstrates proper lifecycle management:

RAII (Resource Acquisition Is Initialization):

  • Constructor acquires resource (the secret key)

  • Destructor releases resource (securely erases key)

  • No manual cleanup needed

  • Automatic cleanup even if exceptions occur

Usage pattern:

Even if sign() throws an exception, the destructor still runs and the key is erased. This is defensive programming—making it impossible to forget cleanup.

Key Type Detection

How does rippled know which algorithm a key uses? The first byte:

This automatic detection means higher-level code doesn't need to track key types—the keys themselves carry the information.

Summary: The Key Lifecycle

Key Takeaways

  1. Randomness is critical: Weak randomness = weak keys = stolen funds

  2. One-way functions enable public-key crypto: Easy to derive public from secret, impossible to reverse

  3. Two algorithms, same security guarantees: secp256k1 for compatibility, ed25519 for performance

  4. Deterministic generation enables backups: One seed can recover many keys

  5. Secure cleanup prevents leaks: Keys must be erased from memory when no longer needed

  6. RAII makes security automatic: Proper C++ patterns prevent human error

In the next chapter, we'll see how these keys are used to create and verify signatures—the mathematical proof of authorization that makes XRPL secure.

Last updated