Skip to content

About

Offline verifier for Predge signed records (ed25519, predge-attest-v1). Node, browser and CLI, zero runtime deps.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

predge-verify

Verify Predge signed records offline: no call to the issuer, no account, no runtime dependencies.

$ npx predge-verify record.json --keys predge-keys.json
AUTHENTIC  kid=3b6551a6439b9bda  10/10 checks passed

Origin: built during the Amazon Developer Hackathon as the verifier used by predge-alexa-mcp.

Why offline verification matters

A signed record is only worth something if you can check it without trusting the party that sent it. If the check is "ask the API whether this is valid", you have moved the trust, not removed it: the issuer can be down, hacked, or lying, and every check leaks what you are looking at. With an ed25519 signature and a published key set, the check is a few lines of local math. You can run it in a voice assistant skill, in a CI job, in an air-gapped audit, or years later when the API is gone.

This matters most for the case that actually happens: a key leaks. Predge publishes a key set at https://api.predge.io/.well-known/predge-keys.json. A key marked revoked must fail regardless of the record's timestamp, because whoever holds a leaked key can backdate. predge-verify enforces that: a record under a revoked key returns key_revoked, even if its signature is mathematically valid. Save the key set, and refresh it when you can.

Install

git clone https://github.com/predgeAI/predge-verify && cd predge-verify && npm install && npm test
node bin/predge-verify.js <file.json|url>

(Not published to npm. npx github:predgeAI/predge-verify <file|url> also works; it builds on install.) Node 18+; the browser build needs a browser with WebCrypto Ed25519.

CLI

predge-verify <file.json|url> [--keys <file>] [--keys-url <url>] [--body-signature "<header>"] [--json]
  • A file may be a full API response, a bare attestation envelope, or an evidence pack.
  • --keys <file>: a saved predge-keys.json. With it nothing touches the network (for a file input). Without it the key set is fetched from api.predge.io.
  • For a URL, the raw body and the x-predge-body-signature / x-predge-body-sha256 headers are checked automatically. For a saved file, save the body unchanged (curl -sD h.txt -o record.json URL) and pass --body-signature.
  • Exit code: 0 authentic, 1 not authentic, 2 usage error.

API

import { verifyRecord } from "predge-verify";           // node:crypto
// import { verifyRecord } from "predge-verify/browser"; // WebCrypto

const result = await verifyRecord(record, {
  keys,            // parsed predge-keys.json (or its keys[] array), OR
  keysUrl,         // where to fetch it (default: api.predge.io/.well-known/predge-keys.json)
  body,            // optional Uint8Array: raw HTTP body, for the detached body signature
  bodySignature,   // optional: value of x-predge-body-signature
  bodySha256,      // optional: value of x-predge-body-sha256
});
// { status, kid, checks: [{ name, ok, detail? }] }

status is one of:

status meaning
authentic every check passed under a listed, non-revoked key
key_revoked the signing key is listed as revoked (checked first, timestamp ignored)
invalid_signature the payload, hash or a signature does not verify (tampering)
unknown_key the kid is not in the key set (or the key set could not be loaded)
malformed not a predge-attest-v1 envelope

Checks, in order: key set and key status (active/retired pass, revoked fails); the envelope key matches the key set; C(payload) == canonical (canonical JSON, a subset of RFC 8785); sha256(canonical) == content_hash; ed25519 signature over canonical; envelope_signature over the whole envelope when present (so kind/data_basis cannot be swapped); and, if you pass the body, sha256(body) and the detached signature over "predge-body-v1\n" + raw body. Retired keys still verify older records.

canonicalJson(value) and verifyWith(backend, ...) are exported too, so you can plug in another crypto backend.

What this does not check: that the facts in the payload are true. Settlement-risk records name chain facts (block, tx hashes) you can re-check on a Polygon RPC; that is outside this library. It proves who signed what, and that nothing changed since.

Format spec: https://data.predge.io/canonicalization.md

Tests

npm test builds and runs node:test suites against a live record fetched from the API (test/fixtures/), a tampered copy, a revoked key (the published 13fa3d18a369e6c7 entry and a generated keypair), malformed input, the body signature and the CLI.

License

Apache-2.0

About

Offline verifier for Predge signed records (ed25519, predge-attest-v1). Node, browser and CLI, zero runtime deps.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages