Open image format · BBP v1

Encrypted regions in a standard image file

An ordinary viewer displays the safe base. A BBP viewer reveals each protected region when it has the required private keys.

Ordinary image fallback Encrypted regions Local processing
protected-regions.bbp.jpgsafe base
Standard viewers see the safe base.2 encrypted regions

BBP principles

01 / additive

Ordinary image fallback

Without the BBP payload, the file remains a valid image containing its safe base.

02 / access

Encrypted regions

Each region is encrypted independently, so the same file can reveal different regions to different viewers.

03 / carriers

Standard image files

BBP stores a JUMBF payload in a supported image carrier. It does not require a special file extension.

Reference implementation

Create and inspect BBP images

Protect regions, open the resulting file, and reveal each region with its matching key.

Encoder and viewer

Build a BBP image

Draw protected regions, assign recipients, then compare the safe base with the regions your loaded keys can open.

Draw regions or compare the safe base with decrypted content.

Drag across the image to add a protected region.

Seeded demo is loading…

Safe-base appearance

Choose how protected regions appear in the ordinary image. BBP does not prescribe this treatment.

For example, the smiley overlay intentionally leaves source pixels visible.

Loaded keys2 keys

Public keys encrypt assigned regions. A matching private key also lets this preview decrypt them.

RegionsCleartext thumbnails

Each region is encrypted for its selected recipient. Overlaps become intersection entities automatically.

Preparing the demo…

HEIF has a carrier implementation but cannot be encoded by this browser demo.

The format

BBP v1 format

BBP adds encrypted region entities to an ordinary image carrier. Viewers without BBP support display the safe base.

At a glance

Payload
Deterministic, definite-length CBOR
Container
JUMBF superbox with label brightblur.bbp
UUID
6262702d-4242-5031-9c1d-4e7aa5330001
Entities
Shuffled region and intersection boxes
Safe base
Full scene with protected regions pixelated
Crypto
Per-entity AEAD and X-Wing recipient wraps

Wire shape

Payload = {
  v:        uint,
  entities: [ Entity, ... ]
}

Entity = {
  kind:  "region" | "intersection",
  body:  bytes,        // AEAD ciphertext
  wraps: [ Wrap, ... ]  // opaque recipients
}

// A compliant viewer paints every entity
// it can open over the safe base.

Processing model

Encoders create the safe base first, seal each original crop independently, shuffle the encrypted entities, encode deterministic CBOR, then bind the same JUMBF superbox to the chosen carrier.

Viewers always paint the safe base first. They trial-open region wraps, paint every authenticated region, then paint an intersection only when every participating key share is available. BBP v1 supports intersections between two or more regions.

Crypto profile

KEM
xwing-draft08
Content
XSalsa20-Poly1305 with a fresh 32-byte key and 24-byte nonce
Wrap KDF
HKDF-SHA-256, salted by the complete X-Wing ciphertext
Recipients
Anonymous trial decryption; no key identifiers or stable hints

Decoder behaviour

No BBP box means an ordinary image. Malformed metadata and unsupported versions are errors, while a wrap that does not open is an expected recipient mismatch. Inaccessible regions remain safely pixelated.

Implementations must bound carrier sizes, CBOR nesting, entity counts, crop sizes, and trial-decryption work before processing untrusted files.

Safe by construction

Non-compliant viewers render the base and ignore the ancillary payload. Losing the BBP payload loses reveal capability; it never exposes a hidden original.

The base still reveals the scene and mosaic geometry. A downloaded file is a frozen grant, and BBP does not survive recompression or metadata stripping.

Implement the draft

The complete draft defines carrier framing, deterministic CBOR, body coordinates, envelope byte layouts, rendering order, error handling, and producer/viewer conformance requirements.

Read the complete specification ↗

Draft boundary

The wire format is explicit enough for independent implementations, but BBP v1 is not frozen. Recipient anonymity and robustness still need independent cryptographic review, followed by frozen carrier and end-to-end fixtures.

Carrier adapters

Supported image formats

The JUMBF payload is unchanged across carriers. Only the binding that places it in the image differs.

WebP

Ancillary RIFF JUMB chunk. The default for the browser demo and a strong photo carrier.

Read · write · web export

JPEG

BBP JUMBF payload in JPEG APP11 segments, with fragmentation for larger metadata.

Read · write · web export

PNG

Private ancillary bBPj chunk with a valid PNG CRC.

Read · write · web export

HEIF

Top-level ISO BMFF uuid box. The carrier implementation exists in @brightblur/bbp.

Read · write · web read

Reference implementation

Packages and applications

The reference implementation includes a format package, a viewer web component, this browser demo, and a native macOS viewer.

@brightblur/bbp

CBOR payloads, X-Wing recipient wraps, detection, and carrier embedding/extraction for WebP, JPEG, PNG, and HEIF.

<bbp-viewer>

A framework-neutral custom element. Give it a URL or File, then use instance keys or one shared keyring for the page.

apps/bbp-preview

The page above is the runnable reference: local redaction, key assignment, export, and reveal with no server dependency.

Swift preview

A fully native macOS preview app reads ordinary and BBP image files, exposes the metadata inspector, and uses the same Rust crypto core.

Open the Swift Package ↗

URL or File source

URLs work declaratively when the response is same-origin or CORS-enabled. Browser files and byte buffers use the src property.

<bbp-viewer
  id="viewer"
  src="/photo.bbp.jpg">
</bbp-viewer>

input.onchange = () => {
  const file = input.files?.[0];
  viewer.src = file ?? null;
};

One keyring per page

Shared keys update every current viewer and become the default for viewers connected later. An explicit instance value remains an override.

import {
  setBbpViewerPrivateKeys
} from '@brightblur/bbp-viewer';

setBbpViewerPrivateKeys([
  privateKey
]);

viewer.privateKeys = [overrideKey];
viewer.useSharedPrivateKeys();

Encode and view

import { bbpEncode } from '@brightblur/bbp';
import '@brightblur/bbp-viewer';

const bytes = await bbpEncode({
  base: redactedImageBytes,
  regions: [{
    bbox,
    epoch: 0,
    pixels: crop,
    recipientPublicKey
  }],
  intersections: []
});

viewer.src = bytes;
viewer.privateKeys = [privateKey];

Adapter contract

To add a carrier, preserve the same payload and implement the four boundary operations below. Then add the carrier to detection and the public dispatch. Keep the binding ancillary so ordinary decoders still render the safe base.

type CarrierAdapter = {
  detect(bytes): boolean;
  embed(base, jumbf): Uint8Array;
  extract(file): Uint8Array | null;
  strip(file): Uint8Array;
};

Where to look

packages/bbp/src/container.ts contains the carrier dispatch and the WebP, JPEG, PNG, and HEIF bindings. packages/bbp/src/encoder.ts assembles the CBOR payload; packages/bbp-viewer/src/index.ts performs local trial-decryption and composition.

Conformance direction

The format document is the normative starting point. The current implementation is a reference for the draft, not a claim that the draft has completed its independent security audit or final test-vector freeze.