Transaction Signing & Verification
← Back to Cryptography I: Blockchain Security and Cryptographic Foundations
Introduction
Digital signatures are the heart of XRPL's security. Every transaction must be signed with the private key corresponding to the sending account. This signature is mathematical proof that the account owner authorized the transaction. Without a valid signature, a transaction is rejected immediately.
In this chapter, we'll trace the complete signing and verification pipeline, understand the differences between secp256k1 and ed25519, and explore why canonical signatures matter.
The Signature: Mathematical Proof of Authorization
A digital signature proves three things:
Authenticity: The signature was created by someone with the secret key
Integrity: The signed data hasn't been modified
Non-repudiation: The signer cannot deny having signed
Transaction Data + Secret Key → Signature
Transaction Data + Public Key + Signature → Valid/InvalidCreating a Signature
The High-Level Interface
// From src/libxrpl/protocol/SecretKey.cpp
Buffer sign(
PublicKey const& pk,
SecretKey const& sk,
Slice const& m)
{
// Automatically detect key type from public key
auto const type = publicKeyType(pk.slice());
switch (*type)
{
case KeyType::ed25519:
return signEd25519(pk, sk, m);
case KeyType::secp256k1:
return signSecp256k1(pk, sk, m);
}
}Parameters:
pk: Public key (for key type detection)sk: Secret key (the signing key)m: Message (the data to sign)
Returns:
A
Buffercontaining the signature bytes
Ed25519 Signing: Simple and Fast
How it works:
Allocate 64-byte buffer
Call
ed25519_signwith message, keys, and output bufferReturn the signature
Properties:
Always produces exactly 64 bytes
Deterministic: same message + key = same signature
Fast: ~50 microseconds
No pre-hashing needed
Signature format:
Where R and S are elliptic curve points/scalars (mathematical details abstracted by the library).
Secp256k1 Signing: More Complex
How it works:
Pre-hash the message: Compute SHA-512-Half of the message
Sign the digest: Use ECDSA to sign the 32-byte hash
Serialize: Encode signature in DER format
Why pre-hash?
ECDSA works on fixed-size inputs (32 bytes)
Messages can be any size
Hashing first normalizes all inputs to 32 bytes
Security proof for ECDSA assumes you're signing a hash
Why DER encoding? DER (Distinguished Encoding Rules) is a standard binary format from X.509:
Deterministic Nonces (RFC 6979):
This is critical for security. ECDSA requires a random "nonce" (number used once) for each signature. If:
The same nonce is used twice with the same key → secret key can be extracted
The nonce is predictable → secret key can be extracted
RFC 6979 derives the nonce deterministically from the message and secret key, making it:
Different for every message
Unpredictable to attackers
Free from random number generation failures
Verifying a Signature
The High-Level Interface
Parameters:
publicKey: The public key to verify againstm: The message that was signedsig: The signature to verifymustBeFullyCanonical: Whether to enforce strict canonicality (important!)
Returns:
trueif signature is validfalseif signature is invalid or malformed
Ed25519 Verification
Canonicality check:
Why check canonicality? Ensures the S component is in the valid range. This prevents malformed signatures from being processed.
Secp256k1 Verification
The digest verification function:
Steps:
Check canonicality: Ensure signature is in canonical form
Parse public key: Convert from compressed format to library format
Parse signature: Decode DER encoding
Verify: Check mathematical relationship between public key, message, and signature
Signature Malleability and Canonicality
The Problem: Signature Malleability
In secp256k1, a signature is a pair of numbers (R, S). Due to the mathematics of elliptic curves:
Where n is the curve order. This means one message has two valid signatures.
Why this is dangerous:
Attack scenarios:
Transaction ID confusion: Applications tracking txID1 won't see the transaction confirmed (it confirms as txID2)
Double-spend attempts: Submit both versions, one might get through
Chain reaction: If txID is used as input to another transaction, that transaction becomes invalid
The Solution: Canonical Signatures
Require S to be in the "low" range:
This makes each signature unique—only one valid signature per message.
Checking Canonicality
Canonicality levels:
Enforcement:
In production, XRPL always sets mustBeFullyCanonical = true to prevent malleability.
Ed25519: No Malleability
Ed25519 signatures are inherently canonical—there's only one valid signature per message. The curve mathematics don't allow the kind of malleability that exists in ECDSA.
This is one of the design advantages of Ed25519 over secp256k1.
Transaction Signing in Practice
Signing a Transaction
What gets signed:
The signature is computed over:
A prefix (
HashPrefix::txSign)All transaction fields (except the signature itself)
Verifying a Transaction
Multi-Signing
XRPL supports multi-signature transactions where multiple parties must sign:
Each signer independently signs the transaction, and all signatures are verified.
Performance Characteristics
Signing Speed
Verification Speed
Why verification speed matters:
Every validator must verify every transaction signature. In a high-throughput system:
Ed25519's speed advantage is significant at scale.
Signature Size
Summary
Digital signatures in XRPL:
Purpose: Prove authorization, ensure integrity, enable non-repudiation
Two algorithms:
secp256k1: Hash-then-sign, DER encoding, requires canonicality checks
ed25519: Direct signing, fixed 64 bytes, inherently canonical
Signing: Secret key + message → signature
Verification: Public key + message + signature → valid/invalid
Malleability: secp256k1 requires canonical signatures to prevent attacks
Performance: ed25519 is faster for both signing and verification
Key takeaways:
Always enforce canonical signatures for secp256k1
Ed25519 is recommended for new accounts (faster, simpler)
Verification happens for every transaction in the network
Multi-signing allows multiple parties to authorize a transaction
In the next chapter, we'll explore hash functions and how they're used throughout XRPL for integrity and identification.
Last updated

