intermediate 60 min

Hash functions in XRPL

SHA-512Half, hash prefixes and ledger namespaces, and how hashing underpins IDs, keys and integrity.

Prerequisites

Complete these before starting this module:

What you'll learn

  • Explain SHA-512Half and why XRPL uses it.
  • Use HashPrefix for domain separation and LedgerNameSpace for ledger keys.
  • Compute transaction and ledger-object identifiers.
Complete this module by self-assessment and a quiz. Jump to assessment

Introduction

≈60 min · Intermediate · builds on Security foundations

Hashes are the workhorses of XRPL, behind every transaction ID, ledger key and Merkle root. In this module you'll learn why the ledger leans on SHA-512Half, how hash prefixes keep different kinds of hashes from ever colliding, and how account addresses are born from RIPEMD160∘SHA256. Small functions, enormous responsibility.

Which hash is used where: SHA-512-Half produces the 32-byte transaction IDs, ledger hashes, SHAMap node hashes, and amendment IDs, while RIPESHA produces the 20-byte account IDs and node public key IDs.

What is a Cryptographic Hash Function?

A cryptographic hash function takes arbitrary input and produces a fixed-size output:

Input (any size)  →  Hash Function  →  Output (fixed size)

"Hello"          →  sha512Half  →  0x7F83B165...
"Hello World!"   →  sha512Half  →  0xA591A6D4...
[1 MB file]      →  sha512Half  →  0x3C9F2A8B...

Required Properties

1. Deterministic

sha512Half("Hello") == sha512Half("Hello")  // Always true
// Same input always produces same output

2. Fast to Compute

// Can hash gigabytes per second
auto hash = sha512Half(largeData);  // Microseconds to milliseconds

3. Avalanche Effect

sha512Half("Hello")  → 0x7F83B165...
sha512Half("Hello!") → 0xC89F3AB2...  // Completely different!
// One bit change → ~50% of output bits flip

4. Preimage Resistance (One-Way)

// Given hash, cannot find input
uint256 hash = 0x7F83B165...;
// No way to compute: input = reverse_hash(hash);

5. Collision Resistance

// Cannot find two inputs with same hash
// sha512Half(x) == sha512Half(y) where x != y
// Computationally infeasible

SHA-512-Half: The Primary Workhorse

In brief: the main hash across XRPL: run SHA-512 and keep the first 256 bits.

Why SHA-512-Half?

// Not SHA-256, but SHA-512 truncated to 256 bits
template <class... Args>
uint256 sha512Half(Args const&... args)
{
    sha512_half_hasher h;
    hash_append(h, args...);
    return static_cast<typename sha512_half_hasher::result_type>(h);
}

Why truncate SHA-512 instead of using SHA-256?

Performance on 64-bit processors:

SHA-512: Operates on 64-bit words → ~650 MB/s on modern CPUs
SHA-256: Operates on 32-bit words → ~450 MB/s on modern CPUs

SHA-512-Half = SHA-512 speed + SHA-256 output size

On 64-bit systems (which all modern servers are), SHA-512 is faster than SHA-256 despite producing more output. By truncating to 256 bits, we get the best of both worlds.

Implementation

Usage Throughout XRPL

Transaction IDs:

uint256 STTx::getTransactionID() const
{
    Serializer s;
    s.add32(HashPrefix::TransactionId);
    addWithoutSigningFields(s);
    return sha512Half(s.slice());
}

Ledger Object Keys:

Keylet keylet::account(AccountID const& id) noexcept
{
    // Ledger object keys use a LedgerNameSpace prefix (not a HashPrefix).
    // indexHash() does sha512Half(std::uint16_t(space), args...).
    return Keylet{ltACCOUNT_ROOT, indexHash(LedgerNameSpace::Account, id)};
}

Merkle Tree Nodes:

Secure Variant: sha512Half_s

// Secure variant that erases internal state
uint256 sha512Half_s(Slice const& data)
{
    sha512_half_hasher h;
    h(data.data(), data.size());
    auto result = static_cast<uint256>(h);

    // Hasher destructor securely erases internal state
    // This prevents sensitive data from lingering in memory
    return result;
}

When to use the secure variant:

  • Hashing secret keys or seeds
  • Deriving keys from passwords
  • Any operation involving sensitive data

Why it matters:

// Regular variant
auto hash1 = sha512Half(secretData);
// SHA512_CTX still contains secretData fragments in memory

// Secure variant
auto hash2 = sha512Half_s(secretData);
// SHA512_CTX is securely erased

RIPESHA: Address Generation

In brief: RIPEMD160 over SHA-256 turns a public key into an account ID.

The Double Hash

Why Two Hash Functions?

1. Defense in Depth

If SHA-256 is broken:
  RIPEMD-160 provides second layer
If RIPEMD-160 is broken:
  SHA-256 provides protection
Breaking both: requires defeating two independent algorithms

2. Compactness

Public Key:    33 bytes
  ↓ SHA-256
SHA-256 hash:  32 bytes
  ↓ RIPEMD-160
Account ID:    20 bytes (40% smaller than public key)

3. Quantum Resistance (Partial)

Quantum computers may break elliptic curves:
  PublicKey → SecretKey (vulnerable)

But cannot reverse hashes:
  AccountID ↛ PublicKey (still secure)

This provides time to upgrade the system if quantum computers emerge.

Usage

SHA-256: Checksum and Encoding

Double SHA-256 for Base58Check

Why double SHA-256?

Historical reasons (inherited from early cryptocurrency designs):

  • Provides defense against length-extension attacks
  • Standard pattern for checksums
  • Well-tested over many years

Checksum properties:

4 bytes = 32 bits = 2^32 possible values

Probability of random corruption matching checksum: 1 in 4,294,967,296

Effectively catches all typos and errors.

Hash Prefixes: Domain Separation

In brief: a distinct prefix per use so a transaction hash can never collide with a ledger-object hash.

// From include/xrpl/protocol/HashPrefix.h
enum class HashPrefix : std::uint32_t
{
    transactionID       = 0x54584E00,  // 'TXN\0'
    txSign              = 0x53545800,  // 'STX\0'
    txMultiSign         = 0x534D5400,  // 'SMT\0'
    manifest            = 0x4D414E00,  // 'MAN\0'
    ledgerMaster        = 0x4C575200,  // 'LWR\0'
    ledgerInner         = 0x4D494E00,  // 'MIN\0'
    ledgerLeaf          = 0x4D4C4E00,  // 'MLN\0'
    accountRoot         = 0x41525400,  // 'ART\0'
};

Why use prefixes?

Prevent cross-protocol attacks where a hash from one context is used in another:

// Without prefixes (BAD):
hash_tx  = SHA512Half(tx_data)
hash_msg = SHA512Half(msg_data)

// If tx_data == msg_data, then hash_tx == hash_msg
// Could cause confusion/attacks

// With prefixes (GOOD):
hash_tx  = SHA512Half(PREFIX_TX,  tx_data)
hash_msg = SHA512Half(PREFIX_MSG, msg_data)

// Even if tx_data == msg_data, hash_tx != hash_msg

Example Usage

Key idea. Domain separation means the same bytes hashed for two different purposes produce two different, non-interchangeable hashes. It quietly prevents a whole class of attacks.

Incremental Hashing

Hash functions can process data incrementally:

// Instead of hashing all at once:
auto hash = sha512Half(bigData);  // Requires loading all data

// Can hash incrementally:
sha512_half_hasher h;
h(chunk1.data(), chunk1.size());
h(chunk2.data(), chunk2.size());
h(chunk3.data(), chunk3.size());
auto hash = static_cast<uint256>(h);

Benefits:

  • Stream large files without loading into memory
  • Hash complex data structures field by field
  • More efficient for large inputs

Example: Hashing a transaction

Serializer s;
s.add32(HashPrefix::TransactionId);
s.addVL(tx.getFieldVL(sfAccount));
s.addVL(tx.getFieldVL(sfDestination));
s.add64(tx.getFieldU64(sfAmount));
// ... more fields ...

return sha512Half(s.slice());

Hash Collisions: Why We Don't Worry

In brief: why finding a collision is astronomically unlikely in practice.

Birthday Paradox

The "birthday attack" on a 256-bit hash requires:

Number of hashes to find collision = 2^(256/2) = 2^128

2^128 = 340,282,366,920,938,463,463,374,607,431,768,211,456

If you could compute 1 trillion hashes per second:
Time = 2^128 / (10^12) seconds
     = 10^25 years

(Universe age ≈ 10^10 years)

Conclusion: Collision attacks on SHA-512-Half are not feasible with current or foreseeable technology.

Collision Resistance in Practice

// XRPL relies on collision resistance for:

// 1. Transaction IDs must be unique
uint256 txID = sha512Half(tx);

// 2. Ledger object keys must not collide
uint256 accountKey = indexHash(LedgerNameSpace::Account, accountID);

// 3. Merkle tree integrity
uint256 nodeHash = sha512Half(leftChild, rightChild);

A collision in any of these would be catastrophic, but the probability is negligible.

Performance Considerations

Hashing Speed

// Benchmark results (approximate, hardware-dependent):

SHA-512-Half: ~650 MB/s
SHA-256:      ~450 MB/s
RIPEMD-160:   ~200 MB/s

For 1 KB transaction:
SHA-512-Half: ~1.5 microseconds

Caching Hashes

Why cache?

  • Merkle tree nodes are hashed repeatedly
  • Caching avoids redundant computation
  • Invalidate when node contents change

Hash Function Summary

Function Output Size Speed Primary Use
SHA-512-Half 256 bits ~650 MB/s Transaction IDs, object keys, Merkle trees
SHA-256 256 bits ~450 MB/s Base58Check checksums
RIPEMD-160 160 bits ~200 MB/s Part of RIPESHA (address generation)
RIPESHA 160 bits ~300 MB/s Account IDs, node IDs

Best Practices

DO:

  1. Use sha512Half for new protocols

    uint256 hash = sha512Half(data);  // Fast and standard
    
  2. Use hash prefixes for domain separation

    uint256 hash = sha512Half(HashPrefix::custom, data);
    
  3. Cache computed hashes when appropriate

    if (cached)
        return cachedHash;
    cachedHash = sha512Half(data);
    return cachedHash;
    
  4. Use secure variant for sensitive data

    uint256 hash = sha512Half_s(secretData);
    

DON'T:

  1. Don't use non-cryptographic hashes for security

    std::hash<std::string>{}(data);  // ❌ NOT SECURE
    
  2. Don't implement your own hash function

    uint32_t myHash(data) { /* ... */ }  // ❌ Don't do this
    
  3. Don't assume hashes are unique without checking

    // Even though collisions are infeasible, handle errors gracefully
    if (hashExists(newHash))
        handleCollision();  // Paranoid but correct
    

Appendix: RFCs and Standards Reference

Introduction

This appendix provides references to the cryptographic standards, RFCs, and specifications that XRPL's cryptography is built upon. Understanding these standards helps you understand why rippled makes certain design choices.

Cryptographic Algorithms

Ed25519 Digital Signatures

RFC 8032 - Edwards-Curve Digital Signature Algorithm (EdDSA)

What it defines:

  • EdDSA signature scheme using Edwards curves
  • Ed25519: EdDSA with Curve25519
  • Ed448: EdDSA with Ed448-Goldilocks
  • Test vectors and implementation guidelines

Key parameters (Ed25519):

  • Curve: Curve25519 (Edwards form)
  • Hash function: SHA-512
  • Public key size: 32 bytes
  • Signature size: 64 bytes
  • Security level: ~128 bits

Why XRPL uses it:

  • Fast signature verification (~5x faster than ECDSA)
  • Simple implementation
  • No signature malleability
  • Modern design with security proofs

secp256k1 Elliptic Curve

SEC 2: Recommended Elliptic Curve Domain Parameters

What it defines:

  • Elliptic curve parameters for secp256k1
  • Curve equation: y² = x³ + 7 (mod p)
  • Prime field size p and generator point G
  • Compression/decompression of public keys

Key parameters (secp256k1):

p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
    FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F

n = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE
    BAAEDCE6 AF48A03B BFD25E8C D0364141

G = (x, y) where:
    x = 79BE667E F9DCBBAC 55A06295 CE870B07
        029BFCDB 2DCE28D9 59F2815B 16F81798
    y = 483ADA77 26A3C465 5DA4FBFC 0E1108A8
        FD17B448 A6855419 9C47D08F FB10D4B8

Why XRPL uses it:

  • Ecosystem compatibility
  • Well-tested (used since 2009)
  • Supported by many libraries and tools

ECDSA Signatures

FIPS 186-4 - Digital Signature Standard (DSS)

What it defines:

  • ECDSA signature algorithm
  • Key generation procedures
  • Signature generation and verification
  • Approved curves (including secp256k1)

Deterministic ECDSA Nonces

RFC 6979 - Deterministic Usage of DSA and ECDSA

What it defines:

  • Deterministic nonce generation for ECDSA
  • Eliminates need for secure random number generation during signing
  • Prevents nonce reuse vulnerabilities

Algorithm:

k = HMAC_DRBG(private_key, message_hash)

Why XRPL uses it:

  • Prevents catastrophic nonce reuse
  • Makes signing deterministic (same message = same signature)
  • No dependency on RNG quality during signing

Hash Functions

SHA-2 Family

FIPS 180-4 - Secure Hash Standard (SHS)

What it defines:

  • SHA-256: 256-bit hash (32 bytes)
  • SHA-512: 512-bit hash (64 bytes)
  • Padding and iteration schemes
  • Test vectors

XRPL usage:

  • SHA-512-Half: First 32 bytes of SHA-512
  • SHA-256: Used in Base58Check checksums
  • Both used in RIPESHA double hash

Why SHA-512-Half:

  • Faster on 64-bit CPUs than SHA-256
  • Same output size (256 bits)
  • Same security level

RIPEMD-160

Original Paper: "RIPEMD-160: A Strengthened Version of RIPEMD"

  • Authors: Dobbertin, Bosselaers, Preneel
  • Published: 1996
  • Hash size: 160 bits (20 bytes)

XRPL usage:

  • Second stage of RIPESHA hash
  • Used in address generation

Algorithm:

RIPESHA(data) = RIPEMD-160(SHA-256(data))

Key Derivation

PBKDF2

RFC 2898 - PKCS #5: Password-Based Cryptography Specification

What it defines:

  • Password-Based Key Derivation Function 2
  • Iterated hashing to slow brute-force
  • Salt for uniqueness

Note: XRPL doesn't use PBKDF2 for key derivation (uses sha512Half of seed), but it's relevant for password-based seed derivation in wallets.

Encoding

Base58

No formal RFC, but based on:

  • Design by Satoshi Nakamoto
  • Excludes similar-looking characters (0, O, I, l)
  • Used widely in blockchain systems

Alphabet:

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

XRPL implementation:

  • Base58Check with 4-byte SHA-256(SHA-256()) checksum
  • Type prefix byte determines first character
  • Compatible with other blockchain systems

Base64

RFC 4648 - The Base16, Base32, and Base64 Data Encodings

XRPL usage:

  • Used in peer handshake (Session-Signature header)
  • Not used for addresses (uses Base58Check instead)

Transport Security

TLS 1.2

RFC 5246 - The Transport Layer Security (TLS) Protocol Version 1.2

What it defines:

  • Handshake protocol
  • Record protocol
  • Cipher suites
  • Certificate verification

XRPL usage:

  • Peer-to-peer communication
  • WebSocket connections
  • RPC endpoints

TLS 1.3

RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3

Improvements over TLS 1.2:

  • Faster handshake
  • Forward secrecy by default
  • Simplified cipher suite negotiation

DER Encoding

ITU-T X.690 - ASN.1 encoding rules

  • Publisher: ITU-T
  • Published: 2015

What it defines:

  • Distinguished Encoding Rules (DER)
  • Used for secp256k1 signature encoding
  • Canonical binary format

Structure:

SEQUENCE {
    r INTEGER,
    s INTEGER
}

Encoded as:
0x30 [length]
    0x02 [r-length] [r]
    0x02 [s-length] [s]

Random Number Generation

NIST SP 800-90A - Recommendation for Random Number Generation

What it defines:

  • Deterministic Random Bit Generators (DRBGs)
  • CTR_DRBG, HASH_DRBG, HMAC_DRBG
  • Entropy requirements
  • Testing procedures

XRPL usage:

  • Relies on OpenSSL's RAND_bytes
  • OpenSSL implements NIST-approved DRBGs

Mnemonic Words

RFC 1751 - A Convention for Human-Readable 128-bit Keys

What it defines:

  • Encoding 128-bit keys as English words
  • 2048-word dictionary
  • Checksum embedded in last word

XRPL usage:

  • Optional seed encoding format
  • Alternative to Base58 for seeds
  • Easier to write down/speak

Example:

Seed (hex):  DEDCE9CE67B451D852FD4E846FCDE31C
Words:       MAD WARM EVEN SHOW BALK FELT
             TOY STIR OBOE COST HOPE VAIN

Cryptographic Best Practices

NIST SP 800-57 - Recommendation for Key Management

What it defines:

  • Key length recommendations
  • Algorithm lifetime
  • Key usage guidance
  • Security strength equivalences

Security Levels:

Security bits Symmetric Hash RSA key ECC key
128 AES-128 SHA-256 3072 256
192 AES-192 SHA-384 7680 384
256 AES-256 SHA-512 15360 512

XRPL compliance:

  • 256-bit secret keys (ECC)
  • 256-bit hashes (SHA-512-Half)
  • ~128-bit security level for Ed25519
  • ~128-bit security level for secp256k1

Implementation Libraries

OpenSSL

Website: https://www.openssl.org/
License: Apache License 2.0

What rippled uses:

  • Random number generation (RAND_bytes)
  • Hash functions (SHA-256, SHA-512, RIPEMD-160)
  • SSL/TLS implementation
  • Some low-level crypto primitives

secp256k1

Repository: https://github.com/bitcoin-core/secp256k1
License: MIT

What rippled uses:

  • secp256k1 curve operations
  • ECDSA signing and verification
  • Public key derivation
  • Signature parsing/serialization

ed25519-donna

Repository: https://github.com/floodyberry/ed25519-donna
License: Public Domain

What rippled uses:

  • Ed25519 signing and verification
  • Public key derivation
  • Fast implementation

Books

  1. "Serious Cryptography" by Jean-Philippe Aumasson
  • Modern cryptography handbook
  • Practical focus
  1. "Cryptography Engineering" by Ferguson, Schneier, Kohno
  • Implementation-focused
  • Real-world protocols
  1. "Applied Cryptography" by Bruce Schneier
  • Classic reference
  • Comprehensive coverage

Papers

  1. "A Graduate Course in Applied Cryptography" by Boneh and Shoup
  1. "High-speed high-security signatures" by Bernstein et al.
  • Ed25519 design paper
  • Performance analysis

Online Resources

  1. Cryptopals Challenges: https://cryptopals.com/
  • Hands-on crypto exercises
  • Breaking weak implementations
  1. Crypto101: https://www.crypto101.io/
  • Introductory book
  • Free online

Standard Bodies

  • IETF: Internet Engineering Task Force (RFCs)
  • NIST: National Institute of Standards and Technology
  • ISO: International Organization for Standardization
  • SECG: Standards for Efficient Cryptography Group

Summary

This module covered the hash functions woven through XRPL. You learned why the ledger leans on SHA-512Half (the first 256 bits of SHA-512), how hash prefixes provide domain separation so a transaction hash can never collide with a ledger-object hash, and how account addresses are derived by RIPEMD160 over SHA-256. Small functions carrying enormous responsibility, behind every id, key, and Merkle root.

To remember:

  • SHA-512Half = the first 256 bits of SHA-512 (faster than SHA-256 on 64-bit hardware, same security target)
  • HashPrefix adds a 4-byte domain tag so a tx hash can never collide with a ledger or validation hash (include/xrpl/protocol/HashPrefix.h)
  • Account ID = RIPEMD160(SHA256(public key))
  • Base58Check checksum = first 4 bytes of double SHA-256
  • A ledger header carries parent_hash plus the two tree roots account_hash and transaction_hash
  • Digest code: include/xrpl/protocol/digest.h; sha512Half_s is the state-wiping variant
  • Collisions are a 2^128 birthday problem: not a practical concern
  • Watch out: hashing the same bytes for two purposes without a prefix is how cross-domain forgeries happen; always use HashPrefix

Next up. Hashes give identity; keys give authority. Next: how key pairs are generated and derived, and what those seed phrases really are.

Assignments

0 of 2 complete

Unlocks

Finishing this module opens up:

XRPL Academy © 2026