intermediate 90 min

Security foundations

The four pillars of blockchain security and the lifecycle of a cryptographic key in XRPL.

Prerequisites

Complete these before starting this module:

What you'll learn

  • Explain confidentiality, integrity, authenticity and non-repudiation in XRPL.
  • Trace a key from entropy to account address.
  • Understand where secrets live and how they're protected.
Complete this module by self-assessment and a quiz. Jump to assessment

Introduction

≈90 min · Intermediate · builds on Case study — the CheckCreate transactor

Watch this short video by XRPL Commons first, then dive into the details below.

Everything valuable in XRPL rests on cryptography, so let's start with what it actually promises. In this module you'll learn the four pillars (confidentiality, integrity, authenticity and non-repudiation) the hard math behind them, and how a single key travels from raw entropy to an account address. It's the ground floor for the whole cryptography phase.

The Cryptographic Promise

In brief: the four guarantees cryptography provides: confidentiality, integrity, authenticity, and non-repudiation.

When you interact with the XRP Ledger, cryptography provides four essential security properties. Understanding these properties, what they mean, why they matter, and how they're achieved, is foundational to everything else in this module.

1. Confidentiality

Confidentiality means that sensitive information remains hidden from those who shouldn't see it.

In XRPL Context

When two rippled nodes establish a connection, their communication is encrypted so that eavesdroppers on the network can't read their messages. The SSL/TLS layer provides this guarantee, ensuring that even though the internet is fundamentally public, peer-to-peer conversations remain private.

How It Works

// From src/libxrpl/basics/make_SSLContext.cpp
// SSL context is configured with strong cipher suites
auto ctx = boost::asio::ssl::context(boost::asio::ssl::context::tlsv12);
ctx.set_options(
    boost::asio::ssl::context::default_workaround |
    boost::asio::ssl::context::no_sslv2 |
    boost::asio::ssl::context::no_sslv3 |
    boost::asio::ssl::context::single_dh_use);

Rippled uses TLS 1.2 or higher with carefully selected cipher suites that provide forward secrecy, even if a node's long-term key is compromised later, past communications remain protected.

Why It Matters

Without confidentiality:

  • Attackers could monitor which transactions nodes are sharing
  • Network topology could be mapped by observing communication patterns
  • Strategic information about ledger state could leak to adversaries

2. Integrity

Integrity ensures that data hasn't been tampered with. A single flipped bit could change "send 1 XRP" to "send 100 XRP", or worse, redirect funds to a different account entirely.

In XRPL Context

When you receive a transaction, you need to know that every byte is exactly as the sender intended. Hash functions provide this guarantee by creating unique fingerprints of data that change completely if even a single bit is modified.

How It Works

// Transaction ID is computed from transaction data
uint256 transactionID = sha512Half(serializedTransaction);

// Any change to the transaction changes the ID completely
// Original: "Payment of 1 XRP"     → ID: 0x7F3B9...
// Modified: "Payment of 2 XRP"     → ID: 0xA21C4...
// Even 1 bit different: completely different hash

The SHA-512-Half hash function used throughout XRPL ensures that:

  • You can't find two different transactions with the same ID (collision resistance)
  • You can't create a transaction that produces a specific ID (preimage resistance)
  • Changing even one bit produces a completely different hash (avalanche effect)

Why It Matters

Without integrity:

  • Transactions could be modified in transit
  • Malicious nodes could alter payment amounts
  • The entire concept of "this transaction" becomes meaningless

Real-World Example

The hash changes so dramatically that any modification is immediately detectable.

3. Authenticity

Authenticity proves the identity of the sender. When a transaction claims to come from a particular account, cryptographic signatures prove that the holder of that account's private key actually created it.

In XRPL Context

Every transaction on XRPL must be signed with the private key corresponding to the sending account. Without this signature, the transaction is rejected. The signature is mathematical proof that only someone with the secret key could have created it.

How It Works

The mathematical relationship between public and secret keys ensures:

  • Only the secret key holder can create a valid signature
  • Anyone with the public key can verify the signature
  • The signature proves authorization for this specific transaction

Why It Matters

Without authenticity:

  • Anyone could claim to be anyone
  • Funds could be stolen by impersonating account owners
  • The entire concept of ownership would collapse

Attack Scenario (Prevented)

Without the victim's secret key, it's computationally infeasible to create a valid signature. The attacker would need to solve the discrete logarithm problem, which would take longer than the age of the universe with all of humanity's computing power.

4. Non-Repudiation

Non-repudiation means that once you've signed something, you can't later deny you signed it. The mathematics of digital signatures make this guarantee absolute: if your private key created a signature, there's no ambiguity, no room for doubt.

In XRPL Context

This property is crucial for a financial system where disputes might arise and proof of authorization is essential. If you signed a payment, that signature is irrefutable proof that you authorized it.

How It Works

Digital signatures create an undeniable link between:

  • The signer (proved by possession of the secret key)
  • The message (what was signed)
  • The time (when it was signed, via timestamps or ledger sequence)
// Alice signs a payment
auto [alicePubKey, aliceSecKey] = generateKeyPair(KeyType::ed25519);
Buffer sig = sign(alicePubKey, aliceSecKey, payment);

// Later, Alice claims: "I never authorized that payment!"
// But the signature proves otherwise:
bool proofOfAuthorization = verify(alicePubKey, payment, sig);
// Returns true - irrefutable proof Alice signed this

Why It Matters

Without non-repudiation:

  • Senders could deny authorizing payments after they complete
  • Dispute resolution would be impossible
  • Legal accountability for transactions wouldn't exist
  • Financial systems couldn't function reliably

Real-World Scenario

Non-repudiation in practice: Alice signs a payment, it enters a ledger, her balance drops, she denies authorizing it; the investigation retrieves the transaction, extracts the signature, verifies it against her public key, and it verifies: whoever held her secret key authorized the payment

Key idea. Signatures give you authenticity and non-repudiation; hashing gives you integrity. Keep those two pairings straight and the rest of the cryptography phase falls into place.

How These Pillars Work Together

These four properties aren't independent, they work together to create a complete security system:

The XRPL security model: transport security provides confidentiality (SSL/TLS) and integrity (hashing); application security provides authenticity and non-repudiation (digital signatures)

Example: A Complete Transaction

Let's see all four pillars in action:

Mathematical Foundations

In brief: the hard problems (discrete logarithm, collision resistance) those guarantees rest on.

The four pillars rest on hard mathematical problems:

For Authenticity and Non-Repudiation: The Discrete Logarithm Problem

Given: PublicKey = SecretKey × G (where G is a generator point)
Hard Problem: Find SecretKey given only PublicKey

Computing PublicKey from SecretKey: microseconds
Computing SecretKey from PublicKey: longer than age of universe

This asymmetry enables public-key cryptography. You can freely share your public key, and no one can derive your secret key from it.

For Integrity: Collision Resistance

Given: hash = SHA512Half(data)
Hard Problems:
1. Find different data' where SHA512Half(data') = hash (preimage)
2. Find data and data' where SHA512Half(data) = SHA512Half(data') (collision)

Computing hash from data: microseconds
Finding data from hash: computationally infeasible

This one-way property makes hashes perfect for integrity checking.

For Confidentiality: Symmetric Key Security

Given: Encrypted = AES_Encrypt(key, plaintext)
Hard Problem: Find plaintext without key

With key: decryption in microseconds
Without key: trying all 2^256 possible keys

TLS negotiates shared secret keys that both parties know but attackers don't.

Trust Model

In brief: who and what you have to trust, and what you do not.

These four pillars enable a trust model where:

You don't have to trust:

  • Network operators
  • Node operators
  • Other validators
  • Anyone else

You only have to trust:

  • Mathematics (that the cryptographic problems are actually hard)
  • Your ability to protect your own secret keys
  • The open-source implementation (which you can audit)

This is the fundamental shift blockchain enables: from institutional trust to mathematical trust.

Security in Depth

Rippled doesn't rely on one cryptographic technique, it uses multiple layers:

Defense in depth: network security (TLS encryption against eavesdropping), transaction security (signatures and hash integrity proving who authorized what and detecting tampering), and protocol security (consensus with majority agreement and Byzantine fault tolerance)

Even if one layer has a vulnerability, others provide protection.

Practical Implications

Understanding these four pillars helps you:

When reading code:

  • Recognize which security property a function provides
  • Understand why certain checks are performed
  • Identify what would break if a step is skipped

When writing code:

  • Choose appropriate cryptographic primitives
  • Implement proper error handling
  • Avoid introducing vulnerabilities

When debugging:

  • Identify which security property is failing
  • Trace the cryptographic operation responsible
  • Understand what went wrong and why

Appendix: Codebase Navigation Guide

Introduction

This appendix provides a comprehensive guide to navigating rippled's cryptographic code. You'll learn where to find specific implementations, how files are organized, and which functions are most important to understand.

Directory Structure

Where the cryptography lives: public headers in include/xrpl (SecretKey.h, PublicKey.h, digest.h, KeyType.h, AccountID.h, csprng.h, secure_erase.h), the implementation in src/libxrpl (protocol, crypto and basics, plus Transactor.cpp for checkSign), and the daemon-side users LedgerMaster.cpp and Handshake.cpp

The ed25519-donna and libsecp256k1 implementations are external dependencies fetched via Conan (they are not in the src/ tree).

Core Cryptographic Files

1. SecretKey.cpp (404 lines)

Location: src/libxrpl/protocol/SecretKey.cpp

Key functions:

Navigate to:

  • Line ~50: randomSecretKey() implementation
  • Line ~100: generateKeyPair() for secp256k1
  • Line ~150: generateKeyPair() for ed25519
  • Line ~200: derivePublicKey() implementations
  • Line ~300: sign() function

2. PublicKey.cpp (328 lines)

Location: src/libxrpl/protocol/PublicKey.cpp

Key functions:

// Verification
bool verify(PublicKey const& pk, Slice const& m, Slice const& sig, bool canonical);
bool verifyDigest(PublicKey const& pk, uint256 const& digest, Slice const& sig, bool canonical);

// Canonicality checking
std::optional<ECDSACanonicality> ecdsaCanonicality(Slice const& sig);
bool ed25519Canonical(Slice const& sig);

// Key type detection
std::optional<KeyType> publicKeyType(Slice const& slice);

Navigate to:

  • Line ~50: verify() function
  • Line ~120: verifyDigest() for secp256k1
  • Line ~180: Ed25519 verification
  • Line ~240: ecdsaCanonicality() implementation

3. digest.cpp (109 lines)

Location: src/libxrpl/protocol/digest.cpp

Key implementations:

// SHA-512-Half hasher
class sha512_half_hasher { /* ... */ };

// RIPESHA hasher
class ripesha_hasher { /* ... */ };

// Helper functions
uint256 sha512Half(Args const&... args);
uint256 sha512Half_s(Slice const& data);  // Secure variant

Navigate to:

  • Line ~20: sha512_half_hasher class
  • Line ~50: ripesha_hasher class
  • Line ~80: Utility functions

4. csprng.cpp (110 lines)

Location: src/libxrpl/crypto/csprng.cpp

Key implementation:

class csprng_engine {
    // Constructor: Initialize entropy
    // operator(): Generate random bytes
    // mix_entropy(): Add additional entropy
};

csprng_engine& crypto_prng();  // Global singleton

Navigate to:

  • Line ~30: csprng_engine class definition
  • Line ~50: Constructor (entropy initialization)
  • Line ~70: operator() (random byte generation)
  • Line ~90: mix_entropy() (additional entropy)

5. tokens.cpp

Location: src/libxrpl/protocol/tokens.cpp

Key functions:

// Base58Check encoding
std::string encodeBase58Token(TokenType type, void const* token, std::size_t size);

// Base58Check decoding
std::string decodeBase58Token(std::string const& s, TokenType type);

// Helpers
std::string toBase58(AccountID const& id);
std::optional<AccountID> parseBase58(std::string const& s);

Finding Specific Functionality

"Where is...?"

Key generation:

src/libxrpl/protocol/SecretKey.cpp
  → randomSecretKey()          // Random generation
  → generateKeyPair()          // Deterministic from seed

Signing:

src/libxrpl/protocol/SecretKey.cpp
  → sign()                     // Sign message
  → signDigest()               // Sign pre-hashed message

Verification:

src/libxrpl/protocol/PublicKey.cpp
  → verify()                   // Verify signature
  → verifyDigest()             // Verify digest signature

Hashing:

src/libxrpl/protocol/digest.cpp
  → sha512Half()               // SHA-512-Half hash
  → sha512Half_s()             // Secure variant

include/xrpl/protocol/digest.h
  → Hash function interfaces

Random numbers:

src/libxrpl/crypto/csprng.cpp
  → crypto_prng()              // Get CSPRNG instance
  → csprng_engine::operator()  // Generate random bytes

Address encoding:

src/libxrpl/protocol/tokens.cpp
  → encodeBase58Token()        // Encode to Base58Check
  → decodeBase58Token()        // Decode from Base58Check

Transaction signing:

src/libxrpl/protocol/STTx.cpp
  → STTx::sign()               // Sign transaction
  → STTx::checkSign()          // Verify transaction signature

Peer handshake:

src/xrpld/overlay/detail/Handshake.cpp
  → makeSharedValue()          // Derive session value
  → buildHandshake()           // Create handshake headers
  → verifyHandshake()          // Verify peer handshake

Task: Understanding Ed25519 Signing

  1. Start at src/libxrpl/protocol/SecretKey.cpp:sign()
  2. Find Ed25519 case in switch statement
  3. See call to ed25519_sign()
  4. Note: External library (ed25519-donna)
  5. External dependency (ed25519-donna), fetched via Conan

Task: Understanding Secp256k1 Verification

  1. Start at src/libxrpl/protocol/PublicKey.cpp:verify()
  2. Find secp256k1 case
  3. Follow to verifyDigest()
  4. See canonicality check: ecdsaCanonicality()
  5. See secp256k1 library calls: secp256k1_ecdsa_verify()
  6. External dependency (libsecp256k1), fetched via Conan

Task: Understanding Address Generation

  1. Start at src/libxrpl/protocol/AccountID.cpp:calcAccountID()
  2. See RIPESHA hash: ripesha_hasher
  3. Implementation in src/libxrpl/protocol/digest.cpp
  4. Double hash: SHA-256 then RIPEMD-160
  5. Encoding: src/libxrpl/protocol/tokens.cpp:encodeBase58Token()

Header vs Implementation

When to read headers:

// Headers show:
// - Function declarations
// - Class interfaces
// - Documentation comments
// - Public API

// Good for:
// - Understanding what's available
// - API reference
// - Quick lookup

When to read implementation:

// Implementation shows:
// - Actual algorithms
// - Error handling
// - Edge cases
// - Performance optimizations

// Good for:
// - Understanding how it works
// - Debugging
// - Learning
// - Contributing

Search Patterns

Using grep to find code:

Using git blame:

# See who wrote/modified code and why
git blame src/libxrpl/protocol/SecretKey.cpp

# See commit that introduced a function
git log -S "randomSecretKey" --source --all

Using tags/symbols:

# Generate ctags for symbol navigation
ctags -R src/ include/

# Jump to definition in vim
# Position cursor on function name, press Ctrl-]

Common Code Patterns

RAII Pattern:

// Look for:
class SomeKey {
    ~SomeKey() {
        secure_erase(/* ... */);
    }
};

Error Handling Pattern:

// Look for:
if (operation_failed()) {
    Throw<std::runtime_error>("Operation failed");
}

Key Type Detection Pattern:

// Look for:
switch (publicKeyType(pk)) {
    case KeyType::secp256k1:
        // ...
    case KeyType::ed25519:
        // ...
}

Tips for Code Reading

  1. Start with tests: Look in src/test for usage examples
  2. Follow the data: Track how data flows through functions
  3. Read comments: rippled has good documentation in code
  4. Use a debugger: Step through code to understand flow
  5. Check git history: See why code was written that way
  6. Ask questions: rippled has active developer community

The Lifecycle of a Cryptographic Key

In brief: how one key travels from raw entropy to a usable account address.

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.

The Birth of a Secret Key

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

// From src/libxrpl/protocol/SecretKey.cpp
SecretKey randomSecretKey()
{
    std::uint8_t buf[32];
    beast::rngfill(buf, sizeof(buf), crypto_prng());
    SecretKey sk(Slice{buf, sizeof(buf)});
    secure_erase(buf, sizeof(buf));
    return sk;
}

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:

The entropy pool: hardware RNG (RDRAND, RDSEED), OS entropy (/dev/urandom, CryptGenRandom, system events) and timing jitter all feed the OpenSSL pool that crypto_prng draws from

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

// Easy direction: secret → public (microseconds)
PublicKey publicKey = derivePublicKey(KeyType::ed25519, secretKey);

// Impossible direction: public → secret (longer than age of universe)
// There is NO function: secretKey = deriveSecretKey(publicKey);

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

case KeyType::ed25519: {
    unsigned char buf[33];
    buf[0] = 0xED;  // Type prefix
    ed25519_publickey(sk.data(), &buf[1]);
    return PublicKey(Slice{buf, sizeof(buf)});
}

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

Secret versus public key: the 32-byte secret key must be kept secret and can sign; the 33-byte public key is shared freely and can verify; together they prove authorization

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:

Generate Key1 → Secret1, Public1
Generate Key2 → Secret2, Public2
Generate Key3 → Secret3, Public3

To backup: Must save Secret1, Secret2, Secret3, ...

Solution with seeds:

Remember one seed → Can regenerate all keys

Seed → Key1 (ordinal 0)
    → Key2 (ordinal 1)
    → Key3 (ordinal 2)
    → ...

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

// Hash the seed to get the secret key
SecretKey generateSecretKey(KeyType::ed25519, Seed const& seed)
{
    auto const secret = sha512Half_s(makeSlice(seed));  // Secure hash
    return SecretKey{secret};
}

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:

detail::Generator g(seed);

auto [pub0, sec0] = g(0);  // First key pair
auto [pub1, sec1] = g(1);  // Second key pair
auto [pub2, sec2] = g(2);  // Third key pair

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:

// From src/libxrpl/protocol/AccountID.cpp
AccountID calcAccountID(PublicKey const& pk)
{
    ripesha_hasher h;
    h(pk.data(), pk.size());
    return AccountID{static_cast<ripesha_hasher::result_type>(h)};
}

The RIPESHA Double Hash

From public key to address: SHA-256 gives a 256-bit digest, RIPEMD-160 reduces it to the 20-byte Account ID, and Base58Check encoding with the type byte yields the human-readable r-address

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:

void signTransaction(Transaction const& tx)
{
    SecretKey sk = loadKeyFromSecureStorage();

    auto signature = sign(pk, sk, tx);

    // sk destructor automatically called here
    // Key material is securely erased
}

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.

secp256k1 public key: 0x02[32 bytes] or 0x03[32 bytes]
ed25519 public key:   0xED[32 bytes]

Summary: The Key Lifecycle

The life of a key: born randomly from crypto_prng or deterministically from a seed, the 32-byte secret key derives the public key through a one-way function, the double hash gives the Account ID, Base58Check gives the address, and the secret is finally erased from memory


Summary

This module laid the cryptographic groundwork. You learned the four pillars, confidentiality, integrity, authenticity, and non-repudiation, the hard mathematical problems they rest on (the discrete logarithm problem for signatures, collision resistance for hashing), and how a single key travels from raw entropy to an account address. Signatures give you authenticity and non-repudiation; hashing gives you integrity.

To remember:

  • Four pillars: confidentiality, integrity, authenticity, non-repudiation
  • Signatures give authenticity + non-repudiation; hashes give integrity
  • Hard problems underneath: the discrete logarithm (signatures) and collision resistance (hashing)
  • Key lifecycle: entropy, seed, key pair, public key, account ID, address
  • The seed is the root secret: everything else derives from it deterministically
  • Key code: include/xrpl/protocol/SecretKey.h and PublicKey.h
  • wallet_propose generates keys; treat its output as radioactive on shared machines
  • Watch out: authenticity of a message is not authorization for an account; regular keys and signer lists separate the two

Next up. You know what the crypto must guarantee. Next, the tool that does most of the work: XRPL's hash functions, and why SHA-512-Half is everywhere.

Assignments

0 of 2 complete

Unlocks

Finishing this module opens up:

XRPL Academy © 2026