Brighton's Blog
← All Series

Binary Formats

1 - RA8 Binary Formats: Overview

RA8D2RenesasEmbeddedBinary FormatsBare-MetalCFile FormatsReverse Engineering

I have been building bare-metal firmware for a Renesas RA8D2 – a 1 GHz Cortex-M85 with 1.6 MB of SRAM – and turning it into an e-reader. Along the way the project grew six binary formats of its own, for books, comics, images, neural-network models and signed firmware.

Read more →

2 - JOF: The Jump-Offset Band-Tile Atlas

RA8D2RenesasEmbeddedBinary FormatsBare-MetalCImage FormatsDEFLATEPNG

This is the format the whole e-reader rests on, and the one I would point at if somebody asked what is actually hard about rendering on a microcontroller.

The short version of the problem: the images this thing has to display are far larger than the RAM it has to display them with, and the formats they arrive in are built in a way that makes partial decoding impossible. Something has to give. This post is the longest in the series, and it sets up the vocabulary – index, seek, working set, edge clamp – that the rest reuse.

Read more →

3 - RBKC: The Chunked .rabook Container

RA8D2RenesasEmbeddedBinary FormatsBare-MetalCEPUBzlibDemand Paging

Books are the reason this project exists, so this is where the e-reader stops being a graphics demo and starts being a reader.

The interesting tension here is that solving one problem creates another. Moving all the EPUB parsing to a host tool makes the device’s job trivial, but it produces a single flat object that is bigger than RAM – so now you need a way to read a piece of it without holding the whole thing. This post is also a useful comparison with the previous one: the two formats put their index at opposite ends of the file, for reasons that are entirely about the producer.

Read more →

4 - RCBZ: The Per-Page Comic Container

RA8D2RenesasEmbeddedBinary FormatsBare-MetalCCBZComicszlib

Comics turned out to be a different problem from books, and I nearly got it wrong by assuming they were the same problem.

The instinct is to reach for the container you already built. That instinct is wrong here, and the post spends a while on why: the unit you index by is a design decision, not an implementation detail, and picking the wrong one costs you several reads and several inflates for every single page turn. There is also a nice security result at the end – the device ends up never running an image decoder at all.

Read more →

5 - ROT1: The Root-of-Trust Signed-Image Trailer

RA8D2RenesasEmbeddedBinary FormatsBare-MetalCSecure BootECDSACryptographyTrustZone

This is the only format in the series with a real adversary.

Everything else here is built to survive accidents: a file truncated by a yanked SD card, a corrupt index, a decompression bomb. Those threat models all stop politely short of somebody who actually means it. Firmware signing does not get that luxury, and the post works through what that changes – including why a checksum is not a weaker version of a signature but a different thing entirely, and why the rollback counter has to sit inside the signed material. Every byte in the worked example comes from a throwaway key generated into a temp directory; no real signing key appears anywhere in this post.

Read more →

6 - NSR1: The Non-Secure Image RoT Header

RA8D2RenesasEmbeddedBinary FormatsBare-MetalCTrustZoneSecure BootLinker ScriptsArmv8-M

Eight bytes. Two fields. This is the smallest thing in the series by a wide margin, and it is here because of a question that has no good answer until you write one down.

Read more →

7 - NPU1: The .npub Ethos-U55 Model Container

RA8D2RenesasEmbeddedBinary FormatsBare-MetalCMachine LearningEthos-U55NPUTensorFlow Lite

The last post in the series takes the idea behind all the others – do the expensive, unbounded work on a host that can afford it – and points it at a neural network.

Read more →