Document of record — transcribed, not authored

byte-verbatim — sha256 over the exact bytes of Phase34_Slice222_GRRC_IndependentVerificationSpec.mdsource bytes (markdown, sha256-pinned) ↗ (14,627 bytes): 6d3cd35cf88dddcf4c4ba6a5109dc7fed940929aa30194a991eee7b7a275756b

The specification below is complete enough that a skeptic can write their own verifier and mirror every input on infrastructure they control (§7). The hosted endpoints at verify.grrc.ai are a convenience over this offline floor — never the only path and never a gate.

Packaged verifier download: coming — this specification is sufficient to build an independent verifier.

GRRC Certification — Independent Verification Specification (v1)

Status: Implementer specification — Phase 34 / Slice 222 (VERIFY-API-COMPLETE). Authored FROM the built resources (drift-resistant). This document defines, completely enough that a skeptic can write their own verifier, how an independent relying party confirms a GRRC robot certification without trusting — or even reaching — GRRC (the offline floor; trust-model (iv-2), the Tank Doctrine extended to verification).

Audience: an insurer's / reinsurer's technical reviewer, a standards body, or any relying party who wants to verify a robot's GRRC certification themselves and mirror the inputs so GRRC withholding can only ever show staleness, never forge validity.

Companions: the Bounded-Claim Statement (Phase34_Slice222_GRRC_BoundedClaimStatement.md — what verification asserts and explicitly does not, owner-authored (iv-1) verbatim) and the API Reference (Phase34_Slice222_GRRC_VerificationApiReference.md). The governance posture is owner-authored in RES_GRRC_TrustModel_v1.0.md (content v1.2); this is engineering only.

No operator/company name appears anywhere in this surface. The root of trust is a crypto-agile key-id + algorithm tag, never a name (CD #864). "GRRC" is an abstract role.


0 — What verification proves (and the two independent legs)

A complete verification runs two independent checks against two distinct keys, and is honest about what each proves:

  1. Genuineness — the clearance carries a certifier signature, verifiable against the published certifier anchor, that the robot cannot forge (the robot holds only the public anchor, never the certifier private key). This is the load-bearing guarantee against self-clearing: fixer ≠ certifier.
  2. Chain integrity — the robot's audit chain is intact and single-headed through a stated sequence: recompute SHA-256 over each entry's canonical encoding, confirm the PrevChainHash → ChainHash linkage, and verify each entry's robot audit-key signature.

Plus revocation currency (the signing key-id is still in the current signed trusted-anchor list) and a stamped-lifetime check.

Two exposure tiers (the (iv-3) privacy boundary, owner-authored, load-bearing):


1 — Cryptographic primitives

Element Value
Signature algorithm tag ECDSA-P256-SHA256-IEEE-P1363
Curve NIST P-256 (secp256r1)
Hash SHA-256
Signature encoding IEEE-P1363 fixed-field r‖s (64 bytes), not DER
Public key encoding SubjectPublicKeyInfo (DER), base64

All signatures in this surface (the grant, the checkpoint, the anchor/revocation statement, and each audit-chain entry) use this one primitive. A verifier checks each with a standard ECDSA-P256 VerifyData/VerifyHash over the stated bytes, the IEEE-P1363 signature format.


2 — The resources (stable, versioned formats)

Each verification input is an independently-fetchable, cacheable, re-hostable resource carrying an explicit FormatVersion. A consumer MUST reject a resource whose FormatVersion it does not understand (fail-closed) — never best-effort parse it. The current versions:

Resource Format version Media type
Verification bundle (offline artifact) schemaVersion 1 application/vnd.grrc.verification-bundle.v1+json
Trusted-anchor set 1 application/vnd.grrc.trust-anchor-set.v1+json
Revocation / anchor-currency statement 1 application/vnd.grrc.revocation-statement.v1+json
Full-record artifact (authorized) schemaVersion 1 application/vnd.grrc.full-record.v1+json

2.1 — The verification bundle / full-record artifact

JSON object (the offline artifact). Public-tier bundles carry RobotAuditPublicKeySpkiBase64 = "" and ChainSegment = []; full-record artifacts populate both.

{
  "SchemaVersion": 1,
  "RobotUuid": "<guid>",
  "GrantPayloadBase64": "<base64 of the grant payload — §3.1>",
  "CheckpointPayloadBase64": "<base64 of the checkpoint payload — §3.2>",
  "AnchorStatementPayloadBase64": "<base64 of the anchor/revocation statement payload — §3.3>",
  "RobotAuditPublicKeySpkiBase64": "<base64 SPKI of the robot audit key, or empty>",
  "ChainSegment": [ <entry>, ... ]   // empty for the public tier
}

Each ChainSegment entry (encrypted envelope only — no plaintext field exists on the wire):

{
  "Sequence": <int64>, "EntryId": "<guid>", "Domain": "<string>", "EventType": "<string>",
  "DomainRecordId": "<guid>", "DecisionCycleId": "<guid|null>",
  "OccurredAt": "<ISO-8601>", "CallerTimestamp": "<ISO-8601|null>",
  "AccessTier": <int>, "SchemaVersion": <int>, "TenantId": "<guid>",
  "PayloadBase64": "<base64 ciphertext envelope>",
  "ChainHashBase64": "<base64 32 bytes>", "PrevChainHashBase64": "<base64 32 bytes>",
  "SignatureBase64": "<base64 robot audit-key signature over ChainHash>"
}

2.2 — The trusted-anchor set

{ "FormatVersion": 1, "Anchors": [ { "KeyId": "<string>", "Algorithm": "ECDSA-P256-SHA256-IEEE-P1363", "PublicKeySpkiBase64": "<base64 SPKI>" } ] }

2.3 — The revocation / anchor-currency statement

{ "FormatVersion": 1, "AnchorStatementPayloadBase64": "<base64 of the anchor-statement payload — §3.3>" }

3 — The signed-content canonical encodings

Every signed payload follows the same two-layer shape: a signed-content canonical byte string (lex-sorted JSON keys, no whitespace) that the certifier signs SHA-256 of; and a payload envelope that stores those exact signed bytes alongside the base64 signature, so a verifier checks the signature over precisely the bytes that were signed (no canonicalization ambiguity). Envelope, for all three:

{ "schemaVersion": 1, "signature": "<base64 IEEE-P1363>", "signedContent": "<base64 of the signed-content bytes>" }

3.1 — Recertification grant (the genuineness leg)

Signed-content JSON, lex-sorted keys, no whitespace:

{"algorithm":"ECDSA-P256-SHA256-IEEE-P1363","expiresAtUtc":"<ISO-8601 O>","faultMarker":"<string>","issuedAtUtc":"<ISO-8601 O>","keyId":"<string>","robotUuid":"<guid D>","supersededDeCertCycleId":<int>,"supersededThroughCycleId":<int>}

The certifier signs SHA-256 of these bytes. faultMarker is the reasoning-integrity fault the clearance supersedes; supersededDeCertCycleId is the specific self-de-certification it clears.

3.2 — Cert-status checkpoint (the public-tier intactness claim)

Signed-content JSON, lex-sorted keys, no whitespace:

{"algorithm":"...","asOfUtc":"<ISO-8601 O>","certStatus":"<token>","headChainHashBase64":"<base64>","headSequence":<int64>,"keyId":"<string>","robotUuid":"<guid D>"}

It asserts "robot R's chain is single-headed and intact through sequence N (head hash H); cert status = {token}; under key-id K; as of {timestamp}." certStatus ∈ {valid,expired,revoked,self-de-certified,superseded} (§5).

3.3 — Trusted-anchor / revocation statement (currency)

Signed-content JSON, lex-sorted keys, no whitespace; trustedKeyIds sorted ordinal + deduped:

{"algorithm":"...","asOfUtc":"<ISO-8601 O>","signerKeyId":"<string>","trustedKeyIds":["<key-id>", ...]}

A clearance's key-id is current (not revoked) iff it appears in trustedKeyIds. Revocation is "pull the anchor" ((vi)): removing a key-id invalidates every clearance under it. GRRC withholding a fresher statement cannot forge currency — the last signed statement stands, and its asOfUtc makes staleness visible to the relying party, who weights it accordingly.


4 — The audit-chain canonical encoding (the chain-integrity leg)

For each ChainSegment entry, recompute ChainHash = SHA-256( canonicalEncoding(entry, prevChainHash) ). The encoding is length-prefixed and big-endian, portable across runtimes. The format version is selected by the entry's own stored SchemaVersion: 0 → v1, 1 → v2, ≥2 → v3. Sequence is NOT in the encoding (it is store-assigned). Byte layout (v3 shown; v2 omits the TenantId field; v1 omits both the schemaVersion stamp and TenantId):

0..3    format version, int32 big-endian (1 | 2 | 3)
[v2/v3] schemaVersion, int32 big-endian
[v3]    TenantId, 16 bytes, .NET Guid.TryWriteBytes layout (MIXED-endian — first three
        fields little-endian, final 8 bytes in declaration order; NOT RFC 4122)
        EntryId, 16 bytes (same MIXED-endian Guid layout)
        Domain length (int32 big-endian) + UTF-8 bytes
        DomainRecordId, 16 bytes (Guid layout)
        DecisionCycleId present-flag (1 byte: 0x00 absent / 0x01 present) + 16 bytes if present
        OccurredAt: int64 big-endian UnixTimeMilliseconds + int16 big-endian UTC-offset minutes
        AccessTier, int32 big-endian
        Payload length (int32 big-endian) + payload bytes (the ciphertext envelope, verbatim)
        PrevChainHash, 32 bytes (all-zeros for the scope genesis)

Guid byte order is the .NET Guid.TryWriteBytes MIXED-endian layout, not RFC 4122. A non-.NET verifier must replicate it: the first three components (Data1 int32, Data2 int16, Data3 int16) are little-endian; the final 8 bytes are in declaration order. EventType and CallerTimestamp are not hashed.

The walk is per scope and genesis-rooted: the first entry's PrevChainHash must be the 32 all-zeros genesis sentinel; each successor's PrevChainHash must equal its predecessor's recomputed ChainHash. Linkage is by PrevChainHash (gap-tolerant on Sequence, so legitimate identity-burn gaps do not false-fail; a deleted in-chain entry still breaks linkage). For each entry, also verify SignatureBase64 is a valid robot-audit-key signature over the 32-byte ChainHash (ECDSA-P256 VerifyHash, IEEE-P1363). The published robot audit public key is carried in the full-record artifact (RobotAuditPublicKeySpkiBase64).


5 — The verification algorithm, in order

Given the bundle (or full-record artifact), the published anchor set, and the verification time asOfUtc:

  1. Decode the three signed payloads (grant §3.1, checkpoint §3.2, anchor statement §3.3). A malformed artifact ⇒ result indeterminate (fail closed).
  2. Genuineness (the certifier signature + the four (vii) conditions):
    • Resolve the certifier anchor for the grant's keyId; confirm the algorithm tag matches.
    • Verify the grant's certifier signature over its signed-content bytes (§3.1) against the anchor's SPKI.
    • Confirm the grant binds the same robot UUID as the artifact and has a well-formed lifetime.
    • If any fails ⇒ genuineness-failed.
  3. Chain integrity:
    • Authorized tier (segment present): run the per-scope walk (§4) over the segment; then confirm the walked head hash equals the checkpoint's headChainHashBase64. If the walk fails or the heads disagree ⇒ integrity-broken.
    • Public tier (no segment): confirm the checkpoint signature (§3.2) against the anchor and that it binds the same robot UUID; intactness rests on that certifier-signed claim through sequence N. If the checkpoint signature fails ⇒ integrity-broken.
  4. Revocation currency: verify the anchor-statement signature (§3.3) against the anchor; confirm the grant's keyIdtrustedKeyIds. Statement signature invalid ⇒ currency unprovable; key-id absent ⇒ revoked.
  5. Lifetime: if asOfUtc > grant.expiresAtUtcexpired.
  6. Determine the bounded status (first failing gate wins): genuineness-failedintegrity-brokenrevokedexpired → an explicit certifier-stated self-de-certified / superseded from the trusted checkpoint → otherwise valid.

OverallVerified is true iff the status is valid.


6 — The bounded result

CertStatus            : valid | expired | revoked | self-de-certified | superseded
                        | genuineness-failed | integrity-broken | indeterminate
OverallVerified       : bool
GenuinenessConfirmed  : bool   (+ GenuinenessKeyId — the certifier key-id)
ChainIntact           : bool   (+ IntactThroughSequence — authorized/offline tier only)
RevocationCurrent     : bool
AsOfUtc               : the verification time
DoesNotAssert         : the owner-authored (iv-1) explicit-negative, VERBATIM (see the Bounded-Claim Statement)

Every result carries the explicit negative so "verified" cannot be read as a broader endorsement of the robot's conduct or the owner's rules. Read it before relying on the result.


7 — Independence, mirroring, and stability


End of the GRRC Independent Verification Specification (v1) — Phase 34 / Slice 222. The claim is not self-referential: this document is sufficient to build an independent verifier. The reference implementation is the offline verifier shipped with RES (Res.Core.GrrcVerification / the Res.Tools.GrrcVerify tool).