Skip to content

v3 envelope support: accept Revettr-style wrapped envelopes with sibling Ed25519 signatures #5

@tomjwxf

Description

@tomjwxf

Follow-up from #3 comment. The @veritasacta/verify CLI currently accepts two receipt shapes:

  • v1 flat (used by protect-mcp, protect-mcp-adk): fields at the top level, {receipt_id, tool_name, decision, signature, public_key, ...}.
  • v2 structured envelope (used by sb-runtime, APS): {payload: {type, decision, action, ...}, signature, pubkey}.

Revettr (see issue #3) ships a third envelope shape for x402 / MPP compliance_risk attestations:

{
  "provider": { "id": "did:web:revettr.com", "category": "compliance_risk" },
  "subject": { "id": "did:web:agent.example.com" },
  "attestation": { "type": "ComplianceRiskAttestation", "payload": { ... } },
  "jws": "<ES256 compact JWS over attestation.payload>",
  "kid": "revettr-attest-v1",
  "algorithm": "ES256",
  "sibling": {
    "jws": "<Ed25519 compact JWS over the same attestation.payload>",
    "kid": "revettr-attest-ed25519-v1",
    "algorithm": "EdDSA"
  },
  "jwks_url": "https://revettr.com/.well-known/jwks.json",
  "revocations_url": "https://revettr.com/.well-known/revocations.json"
}

Ed25519 signatures are cryptographically valid against the JWKS at the referenced URL, but the verifier does not exit 0 on this envelope today because the wrapper shape is not recognized.

Proposed v3 envelope handling

Content-type detection at the top of cli.js verify path:

  1. If the parsed JSON has top-level receipt_id and signature → v1 flat (existing handler).
  2. If it has top-level payload, signature, and pubkey → v2 envelope (existing handler).
  3. If it has top-level jws and either sibling.jws or jwks_urlv3 wrapped (new handler):
    • Fetch JWKS from jwks_url (offline cache if present, else skip with --offline flag).
    • Prefer sibling.jws if present (Ed25519 path). Resolve sibling.kid against the JWKS, verify the JWS compact signature over the JCS-canonical form of attestation.payload.
    • If sibling.jws absent, verify the primary jws against the primary kid. Requires ES256 verification support, which is tracked at #4.
    • Exit 0 on verification success, 1 on failure, 2 on malformed.

Scope

This issue covers only the Ed25519-sibling path. ES256 primary verification is #4 and can land in parallel. The v3 wrapped envelope with only the sibling signature exits 0 today against the existing Ed25519 code path once the dispatch is added.

Test fixture

@AlexanderLawson17 offered to contribute production-signed fixtures (real JWKS, real canonical payload shape, real kid values) in #3. A v3 fixture with a verifiable Ed25519 sibling would let us land this PR with a real conformance test.

Tracker implication

Once this lands, the Revettr row in #3 updates from dual-sig envelope, v3 verifier support pending to npx @veritasacta/verify ✅ (Ed25519 sibling, v3 envelope).

Out of scope

  • Revocations checking (revocations_url field). Separate issue; the v3 dispatch should NOT auto-fetch revocations on every verify.
  • x402 payment receipt cross-check. Separate concern; the Revettr envelope's signature is valid independent of the payment path.
  • Converging v1/v2/v3 into a single canonical shape. Long-term; not blocking.

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions