Lumera Cascade
Concepts

Erasure Coding

How RaptorQ erasure coding ensures permanent data availability across the Supernode network.

Why Erasure Coding?

Simple replication (storing N copies) is wasteful. If you need data to survive 50% of nodes going offline, you need 2x the storage. With erasure coding, you can achieve the same reliability with only ~1.5x overhead.

Cascade uses RaptorQ (RFC 6330), a fountain code that:

  • Encodes a file into N symbols where any K symbols (K < N) can reconstruct the original
  • Has near-zero decoding failure probability
  • Operates efficiently on large files

How It Works in Cascade

Encoding (Upload)

Original File (K source symbols)
         |
         v
  ┌──────────────────┐
  │  RaptorQ Encoder │
  │  (WASM module)   │
  └────────┬─────────┘
           |
           v
  N encoded symbols (N > K)
           |
    ┌──────┼──────┬──────┐
    v      v      v      v
  SN#1   SN#2   SN#3   SN#4 ...
  1. The SDK loads the file into the RaptorQ WASM module (rq-library-wasm)
  2. The encoder produces a layout describing source blocks and encoding parameters
  3. Encoded symbols are distributed across Supernodes
  4. Each Supernode stores a subset of symbols

Decoding (Download)

  1. The SN-API gathers available symbols from responsive Supernodes
  2. As long as at least K symbols are available, the original file is reconstructed
  3. The reconstructed file's BLAKE3 hash is verified against the on-chain record

LEP-1: Layout and ID Derivation

LEP-1 (Lumera Enhancement Proposal 1) defines the deterministic algorithm for deriving layout IDs from the encoding layout.

Layout Generation

const layout = await createSingleBlockLayout(fileBytes, {
  rq_ids_ic: randomSeed,
  rq_ids_max: actionParams.rq_ids_max,
});

ID Derivation Algorithm

Each layout ID is derived deterministically so the on-chain Go implementation can independently verify them:

For i = 0 to rq_ids_max - 1:
  counter = rq_ids_ic + i
  input = Base64(compacted_layout_json) + "." + Base64(adr036_signature) + "." + String(counter)
  compressed = zstd_compress(input, level=3)
  hash = BLAKE3(compressed)
  layout_id = Base58(hash)

Why This Matters

  • Determinism: The same file, signer, and seed always produce the same layout IDs
  • Verifiability: The chain can verify that the claimed layout IDs match the submitted layout
  • Uniqueness: Each symbol gets a globally unique identifier

Index File

The LEP-1 index file aggregates layout IDs and the layout signature:

{
  "version": 1,
  "layout_ids": ["7K9xQ2b...", "3Jm2pNd...", "..."],
  "layout_signature": "base64-encoded ADR-036 signature"
}

This index file is also signed via ADR-036 and included in the MsgRequestAction transaction.

Next Steps

On this page