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:
- If the parsed JSON has top-level
receipt_id and signature → v1 flat (existing handler).
- If it has top-level
payload, signature, and pubkey → v2 envelope (existing handler).
- If it has top-level
jws and either sibling.jws or jwks_url → v3 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.
Follow-up from #3 comment. The
@veritasacta/verifyCLI currently accepts two receipt shapes:{receipt_id, tool_name, decision, signature, public_key, ...}.{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.jsverify path:receipt_idandsignature→ v1 flat (existing handler).payload,signature, andpubkey→ v2 envelope (existing handler).jwsand eithersibling.jwsorjwks_url→ v3 wrapped (new handler):jwks_url(offline cache if present, else skip with--offlineflag).sibling.jwsif present (Ed25519 path). Resolvesibling.kidagainst the JWKS, verify the JWS compact signature over the JCS-canonical form ofattestation.payload.sibling.jwsabsent, verify the primaryjwsagainst the primarykid. Requires ES256 verification support, which is tracked at #4.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
kidvalues) 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 pendingtonpx @veritasacta/verify ✅ (Ed25519 sibling, v3 envelope).Out of scope
revocations_urlfield). Separate issue; the v3 dispatch should NOT auto-fetch revocations on every verify.