Skip to main content

Core complete reference

ULDA Core is the official low-level JavaScript implementation of the ULDA v1 state-lineage protocol. It creates private rolling origins, derives public witnesses from them, and checks whether a candidate has the required hash-linked overlap with a previously accepted witness at a permitted future position.

The npm package name is ulda-core. Its default export is the UldaSign protocol class. ULDA Auth (ulda-auth) is the released client SDK for encrypted JSON resources. ULDA Server is the released single-process backend that stores opaque resources, checks witness transitions, and notifies subscribed clients. Both use Core but are separate products with their own APIs, release cycles, security policies, and licenses.

This repository contains the protocol core itself: codecs, cryptographic operations, modes, runtime orchestration, deterministic test vectors, and single-file distribution bundles.

The protocol and wire-format rules are defined in the ULDA Manifest. Deployment requirements, known limitations, and vulnerability reporting are defined in the Security Policy.

Scope​

The core provides:

  • private origin generation with cryptographically secure randomness;
  • one-step origin advancement through a rolling window;
  • witness generation;
  • directed old-to-new witness verification;
  • skippable mode S and adjacent-only mode X;
  • the default compactV1 package codec;
  • the simpleSig compatibility codec;
  • hex, Base64, and Uint8Array package representations;
  • built-in Web Crypto SHA-1 and SHA-2 hashing;
  • registration of external hash implementations;
  • deterministic official release vectors;
  • modular source code and generated single-file ESM bundles.

ULDA Core does not encrypt data, manage keys, establish the identity of a stream, coordinate competing writers, or sign arbitrary application payloads. Those concerns belong to the protocol or application built around the core.

Runtime requirements​

ULDA Core supports Node.js 22 or later and modern browsers that provide the Web Crypto API:

  • crypto.getRandomValues for private origin generation;
  • crypto.subtle.digest for built-in hash algorithms.

The package is ESM-only and does not provide CommonJS or TypeScript declaration artifacts.

Installation​

Install ULDA Core from npm:

npm install ulda-core

Import the default UldaSign class:

import UldaSign from "ulda-core";

The package root resolves to the readable ESM bundle in dist/ulda-core.js. Files in src/ are included for review, maintenance, and auditing, but they are not supported public import paths.

For a version-pinned browser ESM import from jsDelivr:

<script type="module">
import UldaSign from "https://cdn.jsdelivr.net/npm/ulda-core@1.0.1/dist/ulda-core.min.js";
</script>

The same standalone file is available from UNPKG:

import UldaSign from "https://unpkg.com/ulda-core@1.0.1/dist/ulda-core.min.js";

jsDelivr and UNPKG serve public npm releases automatically; no separate CDN upload is needed. Keep the complete version and file path in the URL. Use an HTTPS page or a secure loopback development context for Web Crypto. These are ES modules and do not create a global browser variable.

The license is available alongside the files. For self-hosting, keep the applicable license and notices with the bundle. Applications using the ULDA Auth standalone browser build already receive its bundled core dependency and do not need this separate import.

Development from source​

git clone https://github.com/ulda-io/ulda-core.git
cd ulda-core
npm ci
npm run release:check

Import the canonical source entry from within the repository:

import UldaSign from "./ulda-core.js";

Quick start​

import UldaSign from "ulda-core";

const ulda = new UldaSign();

// An origin is private state and must not be published or logged.
let origin = ulda.New();

// A witness is the public representation of the current state.
const witness0 = await ulda.sign(origin);

// Advance the private state and create its next public witness.
origin = ulda.stepUp(origin);
const witness1 = await ulda.sign(origin);

// Verification is directed: accepted older state first, candidate second.
const valid = await ulda.verify(witness0, witness1);

console.log(valid); // true

stepUp returns a new encoded origin package and does not mutate the supplied package. The caller must persist the returned origin if the chain is expected to continue from it.

Core lifecycle​

New() -> private origin k -> sign() -> public witness k
|
stepUp()
v
private origin k+1 -> sign() -> public witness k+1

verify(public witness k, public witness k+1)

verify is stateless: the caller supplies both witnesses. An integrating verifier must persist its last accepted witness, check the candidate in the forward direction, and replace stored state atomically only after successful verification.

Calling stepUp several times on the same old origin creates competing branches. Selecting one branch and coordinating multiple writers are outside the core.

Public API​

The supported public API for the 1.0.x release line consists of four methods.

The instance also exposes compatibility facades and internal composition objects from the current implementation. They are unsupported implementation details, are not part of the stable 1.0 API, and may change in minor releases. Applications should depend only on the four methods below.

New(index = 0n)​

Creates a fresh private origin package at the supplied unsigned index.

This method is synchronous. With the default configuration it returns a lowercase hexadecimal string.

The index is metadata only. Creating a new origin with a nonzero index does not connect it to an existing chain.

stepUp(originPackage)​

Decodes an origin, removes its oldest private block, appends a fresh random block, increments the index by one, and returns the newly encoded origin.

This method is synchronous and does not mutate its input.

sign(originPackage)​

Derives a public witness from an encoded private origin.

This method is asynchronous because witness construction uses cryptographic hash operations. It returns the witness in the configured export format.

The method name refers to ULDA witness generation. It does not accept or sign an arbitrary message.

verify(previousWitness, candidateWitness)​

Checks whether candidateWitness has the required hash-linked overlap with previousWitness at an allowed future position:

const valid = await ulda.verify(previousWitness, candidateWitness);

This method is asynchronous and returns a boolean for a well-formed transition. It returns false when:

  • the candidate index is equal to or lower than the previous index;
  • the forward gap is not permitted by the selected mode;
  • height, mode, or hash metadata differs;
  • an authenticated overlap commitment does not match.

Malformed packages and unavailable hash implementations can throw an UldaError.

The argument order is part of the contract. Reversing otherwise valid witnesses returns false.

Verification modes​

ModeAccepted forward gapBehavior
S1 <= gap < NAllows a bounded skip over missing intermediate witnesses
Xgap = 1Requires every adjacent transition

Mode S is the default.

With N = 5, mode S accepts transitions with gaps from one through four and rejects a gap of five or greater. Mode X accepts only the next index.

In the 1.0.x release line, non-default Mode X profiles require separate review. The JavaScript implementation expects compatible total witness lengths and may reject a Mode X profile when its origin-block length differs from the digest length.

Both constructions verify overlapping commitments. The newly introduced tail of a candidate is not authenticated by its predecessor; later transitions constrain it. This behavior is part of the current v1 protocol and is described in detail in the manifest security section.

Configuration​

const ulda = new UldaSign({
fmt: {
export: "hex"
},
sign: {
N: 5,
mode: "S",
hash: "SHA-256",
originSize: 256,
pack: "compactV1",
ageBytes: 4
}
});

Defaults​

OptionDefaultSupported values or meaning
fmt.export"hex""hex", "base64", or "bytes"
sign.N5Rolling-window height
sign.mode"S""S" or "X"
sign.hash"SHA-256"Hash identifier encoded in the package
sign.originSize256Size of each private origin block in bits
sign.pack"compactV1""compactV1" or "simpleSig"
sign.ageBytes4Canonical uint32 age for the current runtime

A valid profile uses 2 <= N <= 255 and a positive, byte-aligned originSize. The current configuration layer does not validate every protocol policy constraint, so callers must use reviewed and consistent parameter sets.

Producers and verifiers for one stream must agree on the pack, mode, height, hash implementation, and origin block size.

Hash algorithms​

The core delegates these algorithms directly to Web Crypto:

  • SHA-1;
  • SHA-256;
  • SHA-384;
  • SHA-512.

SHA-1 is retained for format compatibility and should not be selected for new security designs.

Wire identifiers also exist for SHA3-256, SHA3-512, BLAKE3, and WHIRLPOOL, but their implementations are not bundled with the core. They require an external hasher.

Registering an external hasher​

An implementation for a known wire identifier can be supplied through externalHashers:

const ulda = new UldaSign({
sign: {
hash: "BLAKE3",
originSize: 256
},
externalHashers: {
BLAKE3: {
fn: async bytes => blake3(bytes),
output: "bytes",
size: 256,
ready: true
}
}
});

An arbitrary custom identifier can instead be registered through sign.func:

const ulda = new UldaSign({
sign: {
hash: "MY-HASH-256",
originSize: 256,
func: async bytes => myHash(bytes),
output: "bytes"
}
});

Every participant must use the same custom implementation and output parameters. The custom algorithm code does not identify an arbitrary function without that out-of-band agreement.

Package formats​

compactV1​

compactV1 is the default format. Its compact header carries or implies:

  • window height N;
  • mode S or X;
  • hash algorithm identifier;
  • unsigned state age;
  • reserved flag positions for future backup-related fields, which canonical ULDA v1 packages must leave unused.

Age 0 is represented by an omitted field. A nonzero age is encoded as a four-byte unsigned big-endian integer. The maximum supported age is 4294967295.

The format does not encode package kind, origin block size, stream identity, or payload identity.

simpleSig​

simpleSig is a compatibility format included in the current core. It must be selected explicitly:

const ulda = new UldaSign({
sign: {
pack: "simpleSig"
}
});

The "v1" pack identifier is an alias for simpleSig.

compactV1 and simpleSig use different headers. The core does not auto-detect them, and a runtime configured for one pack must not be expected to decode the other.

Single-file bundles​

The maintained implementation is modular, while the production artifacts are generated as single-file ES modules:

  • dist/ulda-core.js — readable bundle;
  • dist/ulda-core.min.js — minified bundle.

Both bundles are generated from the same source and expose the same API and behavior. The minified file differs only in representation and size.

Build them with:

npm run build

Import a bundle locally or from a static host:

import UldaSign from "./dist/ulda-core.min.js";

The bundles export the same default UldaSign class as ulda-core.js. They do not create a global browser variable. Use them from <script type="module"> or another ESM loader.

Bundling keeps development code split into reviewable modules while avoiding runtime loading of the complete source module graph. Files in dist/ are generated artifacts and must not be edited manually.

Development and verification​

Run the complete test suite:

npm test

Build and verify the distribution bundles:

npm run build
npm run check:bundle

Verify the committed official release vectors:

npm run verify:vectors

Regenerate vectors only when an intentional protocol change requires it:

npm run generate:vectors

Compare supported package formats locally:

npm run compare:packs

Generated vector changes must be reviewed as wire-format or protocol changes, not accepted as routine snapshot updates.

Repository layout​

ulda-core.js Canonical package source entry
ulda-sign.js UldaSign protocol class composition
src/bytes/ Byte conversion and comparison utilities
src/codecs/ compactV1, simpleSig, and compact-header codecs
src/config/ Defaults, normalization, and custom hasher registration
src/core/ Origin, step-up, witness, and verification operations
src/crypto/ Hash and secure-random providers
src/errors/ Structured error type and error codes
src/modes/ Mode S and mode X constructions
src/runtime/ Encoded package orchestration
dist/ Generated single-file ESM bundles
test-vectors/ Deterministic official release fixtures
tests/ Automated behavior and compatibility tests
scripts/ Build, bundle, vector, and comparison tooling
docs/ Detailed implementation documentation

The module layout is an implementation detail. The Manifest, wire format, documentation, and deterministic vectors are provided for inspecting, integrating, testing, and validating official ULDA Core artifacts. They do not grant unrestricted permission to create or validate ports, replacements, or other functionally equivalent offerings; see LICENSE.md.

Additional documentation​

Security status​

Do not report suspected vulnerabilities through a public GitHub issue. Follow the private reporting instructions in the Security Policy.

A complete current origin package is secret state. Witness packages are public and reveal the oldest block of the current origin without additional hashing. Origin blocks must contain fresh random protocol values, not passwords, keys, tokens, or other reusable application secrets. A verifier should persist the last accepted witness and replace it atomically only after successful forward verification.

The repository includes automated tests and deterministic official release vectors, but it does not claim an independent cryptographic audit or a formal security proof. Evaluate the construction and its fresh-tail behavior against the threat model of the system that embeds this core. The normal generator produces the recommended profile, but verify() accepts profile metadata from the supplied witnesses and is not a complete policy for arbitrary attacker-supplied packages. See the security policy for required integration controls and known limitations.

License​

ulda-core is source-available under the ULDA Core Community Source License 1.0. Individual non-commercial use and commercial integration by qualifying organizations with Consolidated Gross Revenue of no more than USD 1,000,000 are permitted subject to the license. Use above that threshold requires a separate commercial license.

Regardless of revenue, using the Covered Materials to create or validate a functionally equivalent ULDA offering requires a separate commercial license. The full definitions, conditions, and mandatory-law exceptions are in LICENSE.md. This is not an OSI-approved open-source license.

The license covers only ulda-core. ULDA Auth and ULDA Server have their own SDK license and Server license. Other separately distributed ULDA products and services require their own terms.

Repository and support​


Reference for Core 1.0.1. Source snapshot.