Overview
Recursive Length Prefix (RLP) is a tiny, header-only C++23 library for building and decoding canonical Ethereum-style RLP — without dragging in half a blockchain node just to serialize a tuple. It keeps the wire format honest, the type system sharp, and the code readable.
- Header-only and lightweight — drop
rlp.hppinto your project and go; no linker drama, no runtime baggage - Ethereum-compatible at the wire level — emits canonical RLP strings and lists exactly as expected by Ethereum tooling
- Canonical by construction — rejects non-minimal encodings, redundant sign extension, and malformed length forms
- Typed integer support — encode and decode unsigned and signed integers with explicit canonical policy
- Boolean support — compact, deterministic mapping for
true/false - Text support — works with
std::string,std::string_view, and string literals - Tuple and aggregate friendly — tuples map naturally to RLP lists, with projection hooks for user-defined types
- Designed for verification — small surface area, doctest-friendly, and easy to reason about at the byte level
- Modern C++23 implementation — concepts, constexpr-oriented design, and clear overload boundaries
Whether you're encoding Ethereum payloads, building compact binary protocols, or just want a sane typed façade over raw RLP bytes — RLP gives you the wire format without the usual suffering.

Features at a Glance
- Minimal footprint — one public header, small API surface, straightforward integration
- Strong type classification — separates integers, text, byte strings, tuples, and projected user types cleanly
- Exact length-prefix handling — computes payload and header sizes explicitly instead of guessing and patching later
- Structured list encoding — tuples and projected aggregates become canonical RLP lists
- Strict decode path — malformed or non-canonical payloads are rejected instead of quietly “helping”
- Customizable projection layer — specialize
from_tuple_t<T>to decode directly into domain types - Predictable semantics — byte-level compatibility with Ethereum RLP, plus optional typed extensions layered on top
- Built for systems code — easy to embed in trading systems, protocol stacks, crypto tooling, or test harnesses
From Value to Wire in Seconds
Get a value onto the wire with just a couple of lines:
#include <rlp.hpp>
#include <array>
#include <tuple>
#include <cstdint>
int main() {
auto payload = std::tuple {
std::uint64_t{42}, true, std::string_view{"dog"}};
auto out = rlp::encode(payload);
}
The resulting byte stream is canonical RLP, ready for protocol use, hashing, persistence, or Ethereum-adjacent tooling.
Decode Back Into Types
Round-trip from wire format into structured C++ values:
#include <rlp.hpp>
#include <array>
#include <tuple>
#include <string>
int main() {
std::array<rlp::byte_t, 7> in{0xc6, 0x2a, 0x01, 0x83, 'd', 'o', 'g'};
auto result = rlp::decode<std::tuple<std::uint8_t, bool, std::string>>(in);
if (!result.ok)
throw std::runtime_error("invalid RLP");
}
Decode Directly Into Your Own Types
Project tuples into domain objects with a tiny specialization:
struct point_t {
std::uint32_t x;
bool y;
};
namespace rlp {
template <>
struct from_tuple_t<point_t> {
using tuple_t = std::tuple<std::uint32_t, bool>;
static constexpr point_t from(const tuple_t& v) {
return {std::get<0>(v), std::get<1>(v)};
}
};
}
point_t directly, while the wire format stays plain old RLP.
Who It’s For
-
Protocol & Blockchain Engineers
- Encode canonical RLP without pulling in a full client stack.
- Build test vectors for Ethereum-adjacent systems.
- Add lightweight RLP support to wallets, tools, and protocol adapters.
- Keep wire-level logic explicit and inspectable.
- Build binary protocol bridges around Ethereum-style payloads.
- Generate deterministic byte payloads for signing, hashing, or transport.
- Validate payloads with strict minimal-form decoding.
- Use strict decoding to catch malformed inputs early.
-
Systems Programmers
- Use a compact binary format with simple length-prefix rules.
- Serialize tuples and small domain objects without reflection magic.
- Keep dependencies low and integration friction near zero.
- Embed the codec inside infrastructure, gateways, or simulators.
- Test byte-exact protocol behavior with minimal ceremony.
- Inspect and fuzz encoding rules in a small, readable codebase.
- Integrate quickly into research or production code without framework sprawl.