Limits
This page collects, from each repository of the release, what it says it does not do. Read it before relying on a verdict.
What this preview does not provide
Protocol release 0.1 is a specification preview (Alpha). Its public API is not stable and may change before 1.0.0, and no independent cryptographic review of the protocol or of its reference verifiers has been done.
This repository does not provide:
- a hosted registry or any other service;
- a service runtime;
- package source code;
- a stable public API or SDK;
- production signing or key-management operations;
- production trust-registry governance;
- the result of an external security audit;
- regulatory approval;
- conclusions about legal ownership;
- correctness of any valuation;
- finality guarantees of any external network;
- service-level commitments.
What release 0.1 does not claim is stated in
introduction.md section 12, “Non-claims”, and
IMPLEMENTATIONS.md says which implementations known to the maintainer
this copy lists.
The requirements no conformance vector exercises, each with the reason or its known limit, are
listed under “Rules without a vector” in traceability/README.md.
The schema package and the two verifiers live in their own repositories, loquitur-schemas,
loquitur-verify-py and loquitur-verify-ts, and each states its own status and limits there.
The conformance corpus comes from loquitur-conformance, which is not published; it reaches
readers as the digest-pinned archive in this repository. This specification defines no HTTP API
and no hosted service, so there is no service status to report.
Known limitations of the protocol in release 0.1
Each of these is stated where its rule is, with what an operator can do about it.
- Pinned roots have no scope. A trust root names no issuer, operator or trust registry, so
every pinned root can authorize a key for every issuer. Pinning the roots of two registry
operators in one trust-root document merges their authority. Operators should pin together only
roots they trust for every issuer, and keep separate trust-root documents otherwise. See
trust-root.mdsection 1. - The envelope is not authenticated. Nothing the issuer signs commits to
envelope_env1.json, so its subject, anchor and provenance members and any embedded registry entry can be rewritten without a key, and the run still passes. A relying party must not treat them as authorized by the issuer. Seebundle-objects.mdsection 4. - The subject reference opening is not checked. A bundle may carry
subject_ref_opening.json, but no check recomputessubject_ref_hashfrom it, so a run passes whether or not it opens the entry’s commitment. A relying party that relies on the subject it names should recompute the value itself. Seeregistry-entry.mdsection 4. - A report does not name its trust material. No normative report member identifies the trust
registry, the root that authenticated it or the trust-root document a run used. Operators should
keep a record of that material with each report. See
report-contract.mdsection 2.
Included from loquitur-protocol/docs/preview-limitations.md. MIT OR Apache-2.0.
What release 0.1 does not claim
This section is informative.
For release 0.1:
- no independent security or cryptographic review of the specification or of either implementation has been done, and no audit of any kind; the maintainer’s own testing, carried out with the help of AI tools, the conformance corpus included, is internal verification and not an audit;
- conformance to this specification, or to the conformance corpus, is not compliance with any law, regulation or standard, and no certification of any kind exists;
- the release is a preview and is not presented as fit for production use or for decisions of real value;
- the specification names no adopter, deployment, customer or partner, and claims none;
- no registry, log, anchoring or other service is operated under this specification;
- a verdict says what section 2 of
threat-model.mdsays it asserts and nothing more: it does not say that the evidence is true, that a value is right, or that an issuer is who it claims to be; - the verdict path contains no AI: no machine-learning model or other learned component takes part in any outcome, which follows from the rules of this specification applied to the inputs.
Included from loquitur-protocol/docs/specification/introduction.md, section 12. CC BY 4.0.
What the Python verifier does not verify
Loquitur governs the evidence behind a valuation; it does not compute valuations.
The verifier does not verify:
- trust registry membership outside the supplied local trust registry;
- issuer signatures without a supplied local
registry_entryandtrust_registry; - issuer authorization without a supplied local
registry_entryandtrust_registry; - trust-registry root authenticity without a root you supply: root-signature verification is
implemented,
PINNED_TRUST_ROOTSships empty and empty means refuse, so a trust registry is authenticated only against a trust-root document passed with--trust-root; - registry inclusion or checkpoint proofs (the
transparencycheck is reserved inverification-checks.md); - chain anchors or their finality (the
anchoringcheck is reserved; seeanchor-commitment.md); - revocation or supersession beyond the fields of the supplied trust registry;
- anything online: it queries no registry and no service;
- valuation correctness;
- KYC, AML or compliance status;
- whether evidence is economically sufficient for an investment decision.
Each report lists, in outcome.not_implemented_capabilities, the capabilities its run did not
have; threat-model.md section 9 names the risk each one leaves with the relying party.
Included from loquitur-verify-py/README.md, “What it does not verify”. MIT OR Apache-2.0.
What the TypeScript verifier does not verify
This verifier does not verify anchor finality or registry inclusion, does not verify
valuation correctness or regulatory compliance, and does not verify an issuer’s real-world
identity. It verifies the trust registry’s root signature only against roots the caller
supplies, and it establishes nothing about who holds a root key: obtaining the trust-root
document through a channel the issuer does not control is the operator’s task
(trust-root.md section 7). A PASS is a statement about evidence integrity and issuer
authorization on local material. It is a precondition for relying on the underlying verdict,
not a verdict on the underlying valuation.
Included from loquitur-verify-ts/README.md, “What it does not verify”. MIT OR Apache-2.0.
Here integrity means the internal consistency of the supplied material: the digests recompute to the values the material declares. It does not mean that the material is unchanged since issuance, and it does not mean that the evidence is true.
Scope and limits of the TypeScript verifier
- Bundle input is a directory. ZIP loading is the host application’s responsibility, which keeps this library free of archive dependencies.
- Node-oriented I/O (
node:fs) is confined toverifyBundleandreadDocumentPath. The I/O-free entry,@loquitur/verify/browser(src/index.browser.ts), exposesverifyBundleFilesover a reader, such asbundleReaderFromMap.npm run build:browseralso bundles that entry into one script,dist/loquitur-verifier.browser.js, which defines the globalLoquiturVerifier; that script is not part of the package. - No bundle member, registry entry or trust registry makes
verifyBundleorverifyBundleFilesthrow: JSON that is not valid UTF-8, repeats a member name, nests deeper than 64 levels, or carries a non-finite number, an integer beyond 2^53-1 or a lone surrogate is a failed check, whether or not the value is hashed. The operator’s own inputs are the exception: a trust-root document or vocabulary document that is not strict JSON is refused withTrustRootErrororVocabularyErrorbefore any evidence is read, as thetrustRootsandvocabulariesitems say. - Containment is checked on every path component immediately before each read and links are refused, but a directory that another process modifies during verification can still change between the check and the read; verify bundles from a location no other process writes to. A hard link is indistinguishable from a regular file and is verified as one.
- Both verifiers refuse every reparse point in a directory bundle, whatever its tag: the Node reader reads it from the type the host’s listing gives each entry. Placeholders of a synchronized folder are reparse points; do not verify bundles from one.
- Alternate data streams attached to a member are not bundle members and are neither inventoried nor verified.
- A file in the bundle that
manifest.jsondoes not declare (other than the manifest, its sidecar,envelope_env1.json, its sidecar and the receipt), and whose name is a portable member name, makes the result REVIEW (bundle_extra_files). A member underattestations/, or nameddocument_index.jsonorclaims_openings.json, is a name this bundle version reserves: REVIEW (bundle_reserved_member), declared or not.verifyBundleFileslearns what the bundle holds from the reader’slistMembers(); the filesystem reader andbundleReaderFromMapimplement it, and a host’s own reader that does not (or returns null) cannot show that nothing is undeclared, so its result is capped at REVIEW. - Every member’s path from the root must be a portable member name (
bundle-objects.mdsection 2): each segment holds onlyA-Z,a-z,0-9,.,_and-, is not.or.., does not end with.or begin with-, and is not a Windows device name such asCONornul.txt, and the whole name is at most 255 bytes. A name outside the rule (a file nameda b.json, a lone surrogate, bytes that are not UTF-8), or two names of one directory that conflict under ASCII case folding, whether the filesystem reader lists it or a host’s reader does, cannot be declared by any manifest: it is never opened, and the run fails withbundle_member_name_invalid. A link in the same bundle is not reported beside it, because an inventory that fails takes the place ofunsafe_bundle_member. Every other error is still reported: a refused name beside amanifest.jsonthat is not JSON givesbundle_member_name_invalidandmanifest_verification_failed. A host that fails to list a directory of the bundle isbundle_inventory_failed, a host failure. bundleReaderFromMaptakes each member as a string or aUint8Array. A host that passes already-decoded strings tobundleReaderFromMaphas already replaced invalid UTF-8; passUint8Arrayvalues to get the same refusal as the Node reader. Build the map withJSON.parseorObject.defineProperty; assigningfiles[name] = valuecannot create a member named__proto__.trustRootstakes the trust-root document oftrust-root.mdsection 3 ({"object_type": "trust_root_document", "schema_version": "v1", "roots": [...]}, each root with itskey_type), never roots read from the registry it authenticates. The whole document is validated when it is read, every root of it whether or not the registry names it, before any evidence is read: a document that breaks section 3 anywhere throwsTrustRootErrorand returns no report, fromverifyBundle,verifyBundleFilesandevaluateTrustRegistryalike, and whatever the other inputs. A document of a well-formed later version is not malformed: the run isUNSUPPORTED_VERSION, andevaluateTrustRegistry, which returns no run, throwsTrustRootError. With well-formed roots, an authorization run that holds at the operator’s evaluation time is PASS when the registry authenticates (ROOT_SIGNATURE_VALID) and FAIL otherwise; without roots it is REVIEW (NO_PINNED_TRUST_ROOT). A root window that does not hold the evaluation time is REVIEW (trust_root_outside_validity_window). A matched root whose secp256k1 point another pinned root also carries, in any SEC1 encoding and whatever its status or key type, isAMBIGUOUS_ROOT_KEY, as two roots under onekey_idare. A document given without a trust registry is validated and then unused.parseTrustRoots,authenticateTrustRegistryandtrustRegistrySigningMessageBytesare exported for hosts that read or sign registries.evaluationTimeis the operator’s evaluation time oftrust-registry-authorization.mdsection 2, a calendar instant of the formYYYY-MM-DDTHH:MM:SSZ: the registry’s and the key’s windows and root authentication are judged at it, and at nothing else. The entry’s owneffective_at,issued_atandanchored_atare never read as a time. An empty value or any other form throwsEvaluationTimeErrorbefore any evidence is read. Without it, the trust registry is still evaluated with the rows that do not read the time, a revoked or suspended key still fails, and a run that would otherwise hold is REVIEW (evaluation_time_not_provided). A registry or key window that does not hold the time is REVIEW (trust_registry_not_current,issuer_key_outside_validity_window), not FAIL. The report states the time inevaluation_time.vocabulariestakes, by kind (asset_type,workflow,anchoring_method), a registered vocabulary document ofverification-vocabularies.mdsection 6 that the operator supplies; a kind not given is judged against the version built into this package (REGISTERED_VOCABULARIES, the protocol’s files as they are), and two documents of one kind are never merged. A document that is not a strict JSON object, breaks section 6 or registers another kind throwsVocabularyErrorbefore any evidence is read. A receipt’sasset_type, or an entry’sasset_typeorworkflow, that is an identifier the vocabulary held does not register makes the run REVIEW (vocabulary_value_unknown), and withholds no check; an unknownanchor.methodchanges nothing. The report records each document held invocabularies: its version, digest and source. This package takes a supplied document already parsed, not as the file’s bytes, so the digest it records for one is the SHA-256 of the document’s RFC 8785 canonical bytes.loquitur-verifyrecords the SHA-256 of the file it reads, so for a file that is not in canonical form the two verifiers record different digests in this informative member.- Verdict narrative rendering (explanations for several audiences) lives in the Python
loquitur-verify[narrative]extra and is not replicated here.
Included from loquitur-verify-ts/README.md, “Scope and limits”. MIT OR Apache-2.0.
What an operator must do that the tool cannot
The verifier answers questions. These are decisions, and no flag makes them:
- Obtain a trust root out of band and pin it. Without
--trust-root, the trust registry proves that some key signed the entry and that the registry the verifier was given vouches for it. Whoever supplied that registry can make both true. Pinning is the difference between section 5 case A and case B. Obtaining the root through a channel the issuer does not control is the operator’s problem entirely. - Supply the evaluation time.
--evaluation-timeis the only clock that judges a key, a registry and a root. Without it, authorization is not established and the run isREVIEW. - Refresh trust material. A registry copy is a snapshot. Decide how old is too old, and enforce it; the tool checks the window written in the file, not whether the file is current.
- Treat
REVIEWas a stop, or name what you accept.--accept-reviewconverts anOFFLINE_REVIEWrun to exit 0 only when every review reason of the run is in the list the operator gives (report-contract.md§4). Acceptingregistry_entry_verdict_requires_reviewdoes not accepttrust_registry_root_not_pinned: each reason accepted is a decision the operator takes on, and a gate that accepts the unpinned root has given up section 5. - Read more than the exit code. At minimum
outcome.reason,checks_requested,checks_established,review_reasons,evaluation_timeand, when the trust registry was evaluated,trust_registry.authorization_status,trust_registry.signature_statusandtrust_registry.trust_registry_root_signature_status. These are normative members (report-contract.md§2), so every conforming verifier reports them. - Bind issuer identifiers to real entities. Out of scope for the protocol and unavoidable for the relying party.
- Decide what a
REVIEWfrom an undeclared bundle member means. The verifier reports the names inmanifest.extra_files; whether the content is material cannot be decided by hashing (bundle-objects.md§1). - Handle disclosed evidence. Retention, access control and destruction of a bundle after verification are entirely the operator’s.
- Keep the verifier honest about itself. Verify the package you run, from a source you trust; a verifier is a trusted computing base, and this document assumes the one executing is the one described.
Included from loquitur-protocol/docs/specification/threat-model.md, section 10. CC BY 4.0.
Platforms
Python verifier
- Python: 3.11 or newer (
requires-python = ">=3.11"). Continuous integration runs the suite on Linux with Python 3.11 to 3.14. - Platforms: the verifier is pure Python. Continuous integration runs its suite on Linux; the suite also passes on Windows locally. macOS is not tested.
- Dependencies:
rfc8785andcryptography; thenarrativeextra addsloquitur-schemas>=0.1.0,<0.2.0. - Protocol: release 0.1 of the Loquitur protocol, as pinned by the conformance corpus above.
Included from loquitur-verify-py/README.md, “Compatibility”. MIT OR Apache-2.0.
TypeScript verifier
- Node.js 22 or later (
enginesinpackage.json). CI runs the suite on Node 22 and 24, on Linux; the suite also passes on Windows locally. macOS is not tested. JSON is decoded by the package’s own tokenizer, never by the host’sJSON.parse, so a value the verifier hashes depends on the document’s text alone. - An ES module consumer: the package is ESM only (
"type": "module"), with no CommonJS build and norequirecondition in itsexportsmap, soimportis the supported way to load it, and it ships its own type declarations. Thetypescondition comes first in each entry of the map, as TypeScript resolves them in order. - A library only: version 0.1 has no command line and the package declares no
bin. The command-line contract ofreport-contract.md(exit code 64 for a usage error) belongs to the command of the Python package,loquitur-verify; this library raises its own faults and has no usage error. - Runtime dependencies:
@noble/curves,@noble/hashesandcanonicalize, each held to the patch line CI tests (~inpackage.json).npm ciin a clone installs exactly the versionspackage-lock.jsonrecords; a tarball carries no lockfile, so installing one resolves each dependency within its patch line.
Included from loquitur-verify-ts/README.md, “Requirements”. MIT OR Apache-2.0.
Project site: loquitur.dev
Written for this site; text licensed CC BY 4.0. Included sections keep the licence of their source, named under each.