Skip to main content

BGW Params

Room encryption (BGW broadcast encryption over BLS12-381) needs a public parameters artifact: a static set of curve points generated once per capacity and reused by every room. Every client — admin and reader — loads the same artifact; rooms pin its identity on-chain at creation.

The artifact

A directory (or HTTP location) with:

manifest.json // capacity, paramsId, paramsRoot, chunk index + hashes
chunks/0.bin
chunks/1.bin
...
Manifest fieldMeaning
capacityUniverse size N — valid member slots are 1..N (default 1,048,576)
paramsId / paramsRootArtifact identity / integrity root — pinned by every room created against it
chunks[]Per-chunk byte length and sha256 — every chunk is verified on load

The artifact is public — it contains no secrets and can be served from a CDN. It is also room-agnostic: one artifact serves any number of rooms (the room's own secret is the admin seed, which is independent of the artifact). Size scales with capacity; at the default capacity the chunks total roughly 200 MB, at capacity 4,096 under 1 MB.

Clients never load the whole artifact: BgwParamsClient fetches only the chunks needed for an operation and caches them, so steady-state usage touches a small fraction of the data.

Pointing the SDK at params

The default source

The SDK resolves params from a configurable default source, so room APIs work without per-call wiring. With nothing configured it uses the built-in default — a public, capacity-1,048,576 artifact hosted on Arweave:

https://arweave.net/erEnI-MC4igmd9SpXuWmoVRiz6zfK-tVqyz5yGjmF8M

It is served as an Arweave path manifest: the base URL returns manifest.json, and chunk i resolves at ${base}/${i}. This is what makes "just create a room" work out of the box — most apps need no params configuration at all.

To use your own artifact (e.g. a different capacity or your own host), pin a base URL or a local directory at startup — see below. You host the artifact once; it is public and serves every room (see Generating an artifact).

Call once at startup; everything resolves lazily from it:

import { configureDefaultBgwParams } from "xpkt-sdk";

configureDefaultBgwParams({ baseUrl: "https://arweave.net/<txid>" }); // Arweave-style: manifest.json at the base, chunk i at `${base}/${i}`
configureDefaultBgwParams({ dir: "/path/to/params" }); // local files (Node)
configureDefaultBgwParams({ manifestUrl: "https://host/params/manifest.json" }); // explicit manifest URL
configureDefaultBgwParams({ loader: async () => myParamsClient }); // fully custom

Per-room override

Every room entry point accepts an explicit BgwParamsClient, which always wins over the default — use this when one process serves rooms with differing params:

import { BgwParamsClient } from "xpkt-sdk";

const engine = await client.loadBgwEngine(); // room-agnostic WASM engine, cached on the client
const params = BgwParamsClient.InitLocal(engine, "/path/to/params");
// or: BgwParamsClient.InitArweave(engine, "https://arweave.net/<txid>")

const room = await client.room({ id: roomId, bgwParams: params });
const adminRoom = await client.roomAdmin({ roomId, seed, bgwParams: params });

Advanced: resolveBgwParams(engine, override?) is the resolution function the SDK uses internally — explicit override first, else the lazily-built cached default; it throws a descriptive error when neither exists.

Capacity and matching

A room created against capacity-N params can hold at most N member slots, and must always be used with the exact artifact it was created with. RoomAdminClient.Load verifies the resolved params root against the room's pinned paramsRoot and rejects mismatches; readers with wrong params fail during key recovery. See Troubleshooting.


Generating an artifact

Generation is a one-time, per-capacity operation. Most applications never generate an artifact — they use the built-in default or point at an operator-provided URL. Larger-capacity artifacts are produced offline and hosted; the SDK's in-process generator below is intended for development capacities and tests.

In TypeScript (development capacities, tests)

BgwParamsGenerator runs through the WASM engine — single-threaded, fine for dev capacities (e.g. 256 generates in seconds):

import { BgwParamsGenerator } from "xpkt-sdk";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";

const dir = "./params-dev";
await mkdir(join(dir, "chunks"), { recursive: true });

const generator = new BgwParamsGenerator({
capacity: 256,
setupSeed: crypto.getRandomValues(new Uint8Array(32)),
saveCb: async (chunkIndex, chunkData) => {
await writeFile(join(dir, "chunks", `${chunkIndex}.bin`), chunkData);
},
});

const manifest = await generator.generateAndSave();
await writeFile(join(dir, "manifest.json"), JSON.stringify(manifest, null, 2));

The resulting directory plugs straight into configureDefaultBgwParams({ dir }) or BgwParamsClient.InitLocal.

BgwParamsClient reference

MemberDescription
InitLocal(engine, dir, manifestFileName?)Load from a local directory (manifest.json + chunks/*.bin)
InitHttp(engine, manifestUrl, resolveChunkUrl?)Load over HTTP; chunks default to chunks/${index}.bin next to the manifest
getManifest()The parsed manifest (cached)
getCapacity()Capacity N as BN
getParamsId() / getParamsRoot()Artifact identity bytes

Chunk integrity (byte length + sha256) is verified on every load, for both local and HTTP sources.