@f0rest8/metamorphic-log
Browser verification + monitor SDK for the
metamorphic-log transparency
log: RFC 6962 / RFC 9162 Merkle inclusion + consistency proofs, C2SP
tlog-tiles checkpoints and signed-note co-signatures (classical Ed25519 and
additive hybrid post-quantum), CONIKS-style index-privacy lookup/absence proofs,
and signed per-namespace policy with declared == observed posture enforcement.
Built for Metamorphic and Mosslet — privacy-first apps by Moss Piglet Corporation — so the browser can monitor the log itself rather than trusting a server.
This package is a WebAssembly build of the metamorphic-log Rust crate. It is a
thin personality over the audited Rust core: it performs no Merkle,
signature, VRF, or policy logic of its own, so every verification and every byte
it computes is identical to the native crate (locked by a cross-language
byte-parity KAT). All cryptographic primitives come from
metamorphic-crypto; there is
no parallel crypto stack.
Verification, not bootstrap trust. A transparency log proves continuity, append-only consistency, and anti-equivocation — it cannot vouch for the first key you ever saw for a peer (a Trust-On-First-Use problem your app must solve out of band). Integrity, authentication, and commitments are post-quantum from day one; only CONIKS index-privacy defaults to a classical ECVRF. Nothing here is FIPS-validated and this package makes no such claim.
Install
npm install @f0rest8/metamorphic-logQuick start
import init, {
verifyInclusion,
verifyConsistency,
checkpointVerify,
} from "@f0rest8/metamorphic-log";
// Initialize the WASM module once before calling any function.
await init();
// All functions are synchronous after init(). Verification predicates return
// `true` on success and THROW on any failure (tamper, forgery, posture
// mismatch, malformed input).
const ok = verifyInclusion(index, size, leafHashB64, proofB64Array, rootB64);Conventions
- Binary values cross the boundary as standard base64 strings (padded, like
btoa/atob). Merkle hashes are 32 bytes; SHA3-512 digests / CONIKS roots are 64 bytes. - Proof audit paths and trusted-key sets are arrays of base64 / text strings.
- C2SP
checkpoint/signed-notebodies andVerifierKeys cross as their canonical UTF-8 text form.
API overview
Inclusion + consistency (the monitor core)
import { verifyInclusion, verifyConsistency } from "@f0rest8/metamorphic-log";
// Throws unless the leaf at `index` is included under `root`.
verifyInclusion(index, size, leafHashB64, proofB64Array, rootB64);
// Anti-equivocation: throws unless the size2 tree is an append-only extension
// of the size1 tree.
verifyConsistency(size1, size2, proofB64Array, root1B64, root2B64);Layer-0 leaf: mosslet/key-history/v1
import {
keyHistoryV1CanonicalBytes,
keyHistoryV1EntryHash,
keyHistoryV1Rfc6962LeafHash,
} from "@f0rest8/metamorphic-log";
// Pass an absent/empty prevEntryHash for the genesis entry.
const leafHash = keyHistoryV1Rfc6962LeafHash(
seq, tsMs, encX25519B64, encPqB64, signingPubB64, prevEntryHashB64,
);
// Feed leafHash straight into verifyInclusion().Checkpoints + signed notes (Ed25519 + hybrid PQ)
import {
verifySignedNote,
checkpointVerify,
checkpointVerifyInclusion,
checkpointVerifyConsistency,
} from "@f0rest8/metamorphic-log";
// Number of trusted signatures that verified (>= 1), or throws.
const n = verifySignedNote(noteText, [vkey1, vkey2]);
// Parse + verify a signed checkpoint note → { origin, size, rootB64, extensions }.
const head = checkpointVerify(noteText, [vkey1]);
// Verify a leaf against a verified checkpoint.
checkpointVerifyInclusion(noteText, [vkey1], leafIndex, leafHashB64, proofB64Array);
// Monitor: verify two checkpoints are a consistent, non-equivocating view.
checkpointVerifyConsistency(olderNote, newerNote, [vkey1], proofB64Array);CONIKS index privacy
import {
coniksVerifyLookup,
coniksVerifyAbsence,
verifyCommitment,
} from "@f0rest8/metamorphic-log";
// Returns the proven value (base64); throws if the proof/VRF/root is invalid.
const valueB64 = coniksVerifyLookup(namespace, vrfPublicB64, rootB64, identityB64, proofB64);
// Throws unless `identity` is provably absent under `root`.
coniksVerifyAbsence(namespace, vrfPublicB64, rootB64, identityB64, proofB64);
verifyCommitment(context, commitmentB64, valueB64, openingB64);Namespace policy: declared == observed
import {
signedPolicyVerify,
policyEnforceCheckpointSigningKey,
policyEnforceCheckpointSignature,
policyEnforceVrfSuiteId,
policyEnforceCommitmentHash,
} from "@f0rest8/metamorphic-log";
// Verify the signed policy → declared posture object.
const policy = signedPolicyVerify(signedPolicyB64);
// { namespace, policySchemaVersion, securityLevel, checkpointSuite,
// commitmentHash, vrfMode, effectiveFrom, createdAt, policyHashB64,
// rfc6962LeafHashB64 }
// Hard-reject any observed posture that disagrees with the declared one.
policyEnforceCheckpointSigningKey(signedPolicyB64, observedPublicKeyB64);
policyEnforceCheckpointSignature(signedPolicyB64, observedSignatureB64);
policyEnforceVrfSuiteId(signedPolicyB64, observedSuiteId); // e.g. 0x03
policyEnforceCommitmentHash(signedPolicyB64, "sha3_256"); // or "sha3_512"License
MIT OR Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.