Verify a CGR attestation (offline)
Verify first. A CGR attestation is a Foundation-signed statement about an agent's reputation. You never have to trust the server that served it: pin the Foundation issuer key once, then verify every attestation yourself — with the @gns-foundation/cgr-verify library, or the language-agnostic recipe below. The Foundation signs; a server serves; you verify.
Pin the issuer key
Pin this key out-of-band (config/env) — do not fetch it at runtime and trust the response:
e7805ce0d5dd06019a2d84c9319baacc1f1516c52ca7d5a0822359918c2893ee
That is the GNS Foundation CGR issuer's Ed25519 public key (hex). Verification fails closed if the key is absent, and rejects any attestation whose issuer_key_id is not exactly this key.
Use the library
npm install @gns-foundation/cgr-verify
import { verifyCGRAttestation } from '@gns-foundation/cgr-verify';
const PINNED = 'e7805ce0d5dd06019a2d84c9319baacc1f1516c52ca7d5a0822359918c2893ee';
const res = await verifyCGRAttestation(attestation, PINNED, {
expectedKey: agentSubjectKey, // optional identity binding
// maxAgeMs: 30 * 86400_000, // optional freshness gate
});
if (!res.valid) throw new Error(`untrusted: ${res.reason}`);
// score is only present on success, read from the now-verified body:
console.log(res.score, res.evidenceMass, res.nResolved, // pooled — backs the score
res.requestedDomain, res.domainNResolved, // domain match
res.scoringScope, res.lastResolvedAt);
Accepts cgr.attestation.v1 / v2 / v3; dependencies are @noble/ed25519 + canonicalize.
The recipe (any language)
The attestation is a flat JSON object. To verify without the library:
- Signed body = the attestation minus the two envelope keys
signatureandevidence_ref. - Canonicalize the signed body with RFC 8785 (JCS) → UTF-8 bytes. (JS
canonicalize, Pythonrfc8785— byte-identical; the committed golden fixtures lock this cross-language.) - Ed25519-verify
signature(hex) over those raw canonical bytes — no SHA-512 prehash — under the pinned Foundation public key.
Two footguns the recipe pins: (a) exclude exactly signature + evidence_ref before canonicalizing; (b) Ed25519 over the raw canonical bytes, not a hash of them.
The five checks
A correct verifier rejects an attestation unless all of these hold:
- Schema is an accepted CGR schema (
cgr.attestation.v1 / v2 / v3). - Issuer is
gns-foundation. issuer_key_idequals your pinned key (never trust the key named on the wire).- Neutrality / binding:
subject_keyis not the issuer key; and, if you are binding an identity,subject_keyequals the key you expected. - Signature verifies (Ed25519 over the JCS canonical bytes).
Any single-field tamper — score, freshness, or the scope fields — changes the canonical bytes and fails check 5.
What a verified attestation tells you (honest-scope)
Once verified, read the values from the signed body (never from an unverified attestation):
cgr_scorewith its evidence — a bare score is never obtainable. The pooledconfidence(n = α+β) andn_resolvedback the score;domain_n_resolvedbacks the requested-domain match.scoring_scope: "pooled"— the score pools all of the subject's judgment evidence into one dimension; it is not a per-domain score.requested_domainrecords which capability domain was matched, not a domain-specific score.last_resolved_at— freshness, signed, so staleness cannot be doctored by an intermediary.
Key rotation (continuity) is verified separately from the rotation proofs at /v1/cgr/rotations; this recipe verifies the base attestation signature + binding.
Cross-language parity
The offline recipe is locked by committed golden fixtures (cgr_attestation_v2/v3_jcs.golden.json) that carry the exact canonical bytes plus a signature under a known test key — so a from-scratch verifier in any language can prove byte-for-byte parity with the reference.
References
@gns-foundation/cgr-verify— the offline verifier (recipe + fixtures).- CGR API reference — record governed decisions and outcomes; read reputation.
- What is Capability-Grounded Reputation? — the model behind the attestation.