Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Tenant scope keys

TenantScopeKeyring manages versioned, 32-byte keys inside a tenant and scope. It coordinates lifecycle state; a customer-owned TenantScopeKeyStore remains the persistence and destruction boundary. DataPrism does not receive or host the key material.

import {
  MemoryTenantScopeKeyStore,
  TenantScopeKeyring,
} from "@dataprism/sdk/tenants";
 
const keys = new TenantScopeKeyring({
  tenantId: "tenant-123",
  scopeId: "documents",
  store: new MemoryTenantScopeKeyStore(),
});
 
await keys.create(); // creates version 1
 
const version1 = await keys.resolve(1);

The keyring can be passed directly to the file pipeline as its customer-owned resolver. Each operation requests the exact version recorded by the file:

import { FilePipeline } from "@dataprism/sdk/files";
 
const pipeline = new FilePipeline({
  providers,
  standard,
  scopeKeyResolver: keys,
});
 
await pipeline.upload("before.bin", beforeBytes, uploadOptions); // version 1
await keys.rotate();
await pipeline.upload("after.bin", afterBytes, {
  ...uploadOptions,
  scopeKeyVersion: 2,
});

The memory adapter is non-durable and intended for tests and examples. Production applications must implement TenantScopeKeyStore against storage they own. Its compare-and-create operation must be atomic so concurrent rotations cannot reuse or skip a version.

Key generators and store adapters may return a Node Buffer or a plain Uint8Array. The keyring makes independent byte copies before clearing its temporary material. Store adapters must do the same when retaining a key or returning one from resolve: use Uint8Array.from(bytes) or another copying operation, not Buffer.slice(), which shares the original bytes. A resolved copy belongs to the caller and must be cleared when no longer needed.

Three separate keys

The Prism opening key, tenant scope keys and filename-addressing key have different jobs:

KeyPurposeWhere it comes from
Prism opening keySeals metadata, provider settings and file indexesThe dashboard derives it from an account signature; SDK callers can supply a secret through DataPrismKey.fromSecret.
Tenant scope keyDerives encryption keys for file chunks and manifestsTenantScopeKeyring creates random, versioned 32-byte keys in the customer-owned key store.
Filename-addressing keyDerives stable, scoped file IDs from filenamesTenantScope.bindPrism creates a separate, stable 32-byte key in the customer-owned prism binding store.

The public cloudId cannot reproduce any of these secrets. A TenantPrismBindingStore must retain the addressing key across process restarts and scope-key rotations. TenantScope.openPrism reads an existing binding; it does not generate a replacement key if the binding is missing. The memory binding store, like the memory key store, is for tests and examples.

TenantPrism.standard(key) supplies that addressing key to CloudStandard; the caller still supplies the separate Prism opening key. When building CloudStandard directly, provide a stable fileDataIdScopeKey yourself. Do not replace it with each new tenant scope-key version, or filename lookups will change. See Scoped file identifiers.

V3 uploads

V3 writes are available through an explicit publicIndex upload option. They require scoped filename addressing, a customer-held scope key or resolver, and customer-self-custody-v1. A TenantPrism.filePipeline supplies the scoped standard and resolver and pins the latest active scope-key version when the pipeline is built; it does not select V3 automatically.

For a pipeline configured with those keys:

await pipeline.upload("report.pdf", reportBytes, {
  ...uploadOptions,
  publicIndex: {
    derivationPolicy: "tenant-scope-key-v1",
    custody: "customer-self-custody-v1",
    encodingMode: "reed-solomon-dense-cauchy-v1",
  },
});

An on-chain V3 upload also needs an explicit contentAnchorCommitter, such as AccountExecution; a configured cloudId without it is rejected before shard writes. This does not imply relayed-write support or support in every deployed contract. V3 overwrite: true is unsupported: use a new entry. An offline pipeline with no cloudId can return the sealed slot for customer-managed submission.

Each new V3 upload records a randomized content commitment with a fresh 32-byte nonce and custody.recovery: "none". DataPrism holds no recovery key and cannot restore a lost or destroyed customer scope key. The commitment is checked on download; it is not a substitute for encryption or scoped filename addressing.

Without publicIndex, uploads retain the V2 path; existing legacy/V2 indexes remain readable. Enabling V3 does not migrate those entries. Customer KMS adapters are not implemented. SDK distribution remains restricted pending the licence decision.

Lifecycle rules

  • create() creates version 1 only when the scope does not exist.
  • rotate() creates the next version while preserving older versions for historical reads.
  • resolve(version) is the only keyring method that returns key bytes. Do not log or serialize its return value.
  • destroy() records the irreversible destroying state before asking the store to remove each version. Rotation cannot resume after this point.
  • Destruction reports succeeded only when every recorded version is a tombstone. A failed adapter operation reports that recorded key material may remain and can be retried.

Lifecycle results contain the tenant, scope, version, derivation and custody identifiers, but no key or key fingerprint. observedAt is the caller's local observation time; it is not an independently established timestamp.

Claim boundary

A successful result describes key material recorded by that store. It does not prove that undisclosed copies, application logs, process memory or backups were removed. JavaScript memory zeroing is also not a hardware-backed destruction guarantee.

Resolver-backed reads, health checks, repair and orphan cleanup use the exact key versions recorded in the sealed index. Lifecycle observations can be retained in a customer-owned evidence journal; their presence does not broaden the destruction claim above.

Copyright © 2026 DataPrism.