Reference verifier source for Dynamic Feed signed envelopes and signing-key lifecycle policy. The security boundary is deliberately split:
crypto_validmeans the Ed25519 signature, exact metadata, canonical bytes, and key-ID binding passed;ok/ policy acceptance additionally requires an acceptable signer in a validated lifecycle registry whose source the verifier authenticated;- a signature proves integrity under that key, not objective truth, safety, or legal compliance.
Earlier published verifiers accepted a flat public-key map and had no retired/compromised signer
policy. The former signing key df-ed25519-4cb32e72f333 is now classified compromised using the
conservative boundary 2026-07-11T00:00:00Z. Its public bytes are retained so historical signature
mathematics remain inspectable, but that key must never produce a live policy-accepted result.
The hardened Python and npm versions in this repository remain release targets. The Rust target has been published and independently installed from crates.io; that Rust release does not complete the multi-ecosystem package rotation:
| Ecosystem | Affected version/source | Hardened version | Release status |
|---|---|---|---|
PyPI dynamicfeed-verify |
<= 1.0.2 |
1.0.3 |
Pending; publishing credentials unavailable |
npm @dynamicfeed/verify |
<= 1.0.1 |
1.0.2 |
Pending; publishing credentials unavailable |
crates.io dynamicfeed-verify |
1.0.0 (and affected prior source 1.0.1) |
1.0.2 |
Published and registry-verified 2026-07-11 |
| C# sample | all current source | quarantined, transport-only | Not a package |
Rust dynamicfeed-verify 1.0.2 was built from source/tag commit
95e033efd252e9e97029c0ef97a3ccddad9b6351 and tagged rust-v1.0.2. crates.io records
published_at as 2026-07-11T16:14:45.939696Z and a crate size of 29597 bytes. The crates.io
artifact and GitHub release asset have the same SHA-256 digest:
798bc660b4e9abe25c7f62bcd8007cf1897ca0d8607d975d8b9ba0b8d841d019. A clean install from
crates.io returned POLICY_ACCEPTED for the active signer and CRYPTO_VALID with
LIFECYCLE_REJECTED for the former compromised signer.
Do not announce a clean multi-ecosystem package rotation until the pending Python and npm artifacts are built from their reviewed commits, published through their normal release controls, installed from each registry into a clean environment, and recorded with artifact digests and provenance.
See SECURITY.md for the full advisory.
SIGNING_KEY_LIFECYCLE.jsonis the revieweddf-signing-key-registry/v1snapshot. It retains active and historical public bytes with explicit lifecycle status andregistry_revision.KNOWN_KEYS.jsonis a deprecated compatibility archive. It is intentionally not a flat map and cannot honestly authorize the compromised key.- The production service compatibility endpoint
/.well-known/keysis active-key-only following the 2026-07-11 service cutover. The former key is absent from active discovery and is retained only in the lifecycle registry withcompromisedstatus. This repository records verifier source; that completed service cutover does not mean the pending Python and npm target package versions are published.
The current-domain registry is an operational disclosure, not an independent trust root. A
security-sensitive verifier should pin a reviewed registry out of band, authenticate updates, and
persist the highest authenticated registry_revision outside the document.
- Strictly parse JSON and reject duplicate object names, malformed numbers, raw controls, and trailing bytes.
- Require exactly
Ed25519andjson-sorted-compactsignature metadata. - Preserve both frozen receipt conventions: verify without
signaturefirst, then (only when needed) without bothsignatureand a legacy post-signatureanchor. - Derive
key_idfrom the SHA-256 fingerprint of the raw public key. - Validate the lifecycle registry, its key/fingerprint relationships, chronology, policy fields, active-key uniqueness, and revision floor.
- Accept only the current active key in live mode. Retired keys are non-live historical material; compromised keys are never policy accepted.
- Keep historical snapshot inspection explicit and non-actionable: it can report signature mathematics and policy-as-of state but never returns an overall live acceptance.
anchor_authenticated=true means an attached anchor was inside the signed bytes.
anchor_authenticated=false means the frozen legacy post-signature attachment was outside them.
Neither state independently validates an RFC 3161 or OpenTimestamps proof; these libraries do not
claim full timestamp-proof verification.
| Path | Status |
|---|---|
clients/python |
Python lifecycle-aware verifier, target 1.0.3 |
clients/js |
JavaScript/TypeScript lifecycle-aware verifier, target 1.0.2 |
clients/rust |
Rust crate dynamicfeed-verify, lifecycle-aware target 1.0.2 |
clients/csharp |
Quarantined transport-only sample; no reference-verifier claim |
examples/verified-agent |
Verify-before-use example; never an actuator |
tests/vectors |
Shared canonicalization and frozen receipt fixtures |
reliability |
Separate non-cryptographic reliability vocabulary and validators |
This repository's clients/rust is the source for the crate named
dynamicfeed-verify. The distinct monorepo crate named df-verify (0.1.2 target) is maintained at
Dynamic-Feed/packages/df-verify-rs; it is not source-identical or package-identical. Its Cargo
repository metadata must point to its actual source location (or that exact source must be added
here under an unambiguous path) before publication.
Python:
python -m pip install -e clients/python pytest
python -m pytest clients/python/tests
python tests/verify_vectors.pyJavaScript:
npm install --prefix clients/js
npm test --prefix clients/js
node tests/verify_vectors.mjsRust:
cd clients/rust
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-featuresRotation guardrail:
python scripts/check_rotation_policy.pyPython:
import json
from dynamicfeed_verify import verify
registry = json.load(open("SIGNING_KEY_LIFECYCLE.json"))
result = verify(
envelope,
lifecycle_registry=registry,
registry_source_authenticated=True, # caller authenticated this pinned file
)
if not result["ok"]:
raise RuntimeError(result["error"])JavaScript:
import { verify } from '@dynamicfeed/verify';
const result = await verify(rawEnvelopeText, {
lifecycleRegistry: pinnedRegistry,
registrySourceAuthenticated: true,
});
if (!result.ok) throw new Error(result.error);Rust:
let registry = dynamicfeed_verify::LifecycleRegistry::parse_with_options(
®istry_text,
dynamicfeed_verify::RegistryValidationOptions {
registry_source_authenticated: true,
..Default::default()
},
)?;
let result = dynamicfeed_verify::verify_with_registry(&raw_envelope, ®istry)?;
assert!(result.accepted);- Specification surface: https://dynamicfeed.ai/standard
- Browser verifier: https://dynamicfeed.ai/proof
- Lifecycle registry endpoint: https://dynamicfeed.ai/.well-known/signing-key-registry.json
- Active-key compatibility endpoint: https://dynamicfeed.ai/.well-known/keys
MIT.