Skip to main content

Test Vectors

This appendix provides normative test vectors for JCS canonicalization (RFC 8785) and Ed25519 signature verification. Implementations MUST produce identical outputs for these inputs. Refresh these vectors when the response schema changes.

Test Key Pair

The test vectors use the Ed25519 key pair from RFC 8032, Section 7.1, Test Vector 1.

FieldValue
Private key (hex)9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60
Public key (hex)d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a
Public key (base64url)11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo
kidtest-key-1

Vector 1 — Minimal Response

A response with no signals and no assessment. Tests baseline key ordering and signature verification. meta.url is present (MUST per ADR-007 — Binding the Signed Response to the Request); meta.context is omitted (MAY) to exercise the no-context path.

Input (signing input — response body without signature):

{
"meta": {
"responseId": "550e8400-e29b-41d4-a716-446655440000",
"entityId": "d6f2fdf4-f829-4ce6-a1cc-e2bd957709db",
"status": "verified",
"url": "https://www.example.org/de/products/123",
"timestamp": "2026-03-23T14:30:00Z",
"expires": "2026-03-24T14:30:00Z"
},
"signals": [],
"kid": "test-key-1"
}

Expected JCS output:

{"kid":"test-key-1","meta":{"entityId":"d6f2fdf4-f829-4ce6-a1cc-e2bd957709db","expires":"2026-03-24T14:30:00Z","responseId":"550e8400-e29b-41d4-a716-446655440000","status":"verified","timestamp":"2026-03-23T14:30:00Z","url":"https://www.example.org/de/products/123"},"signals":[]}

Expected values:

FieldValue
SHA-256 of JCS bytes059a554cdc329fd7f23fbc5550be0f2300ae0a443b3f5733aca61c59a117c0af
Ed25519 signature (base64url)EeHWDKMFJ122G3d3V6VO0URuA0jfH5cF-7hC5c7fF9FHwNE3XCqbu2ky1Fm_BkbB4F854lkjCYfk-00l3T08CA
Ed25519 signature (hex)11e1d60ca305275db61b777757a54ed1446e0348df1f9705fbb842e5cedf17d147c0d1375c2a9bbb6932d459bf0646c1e05f39e259230987e4fb4d25dd3d3c08

Key observations:

  • Top-level keys sort as kid, meta, signals (lexicographic order by UTF-16 code units).
  • Nested keys inside meta sort independently: entityId, expires, responseId, status, timestamp, url.
  • meta.context is absent — agents that sent no context query parameter still verify successfully.
  • No whitespace between tokens.

Vector 2 — Response with Signals and Assessment

A response with two signals and an assessment. Tests nested objects, arrays, mixed types (strings, numbers), and deeper key ordering. Both meta.url and meta.context are present (per ADR-007 — Binding the Signed Response to the Request).

Input (signing input — response body without signature):

{
"meta": {
"responseId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"entityId": "d6f2fdf4-f829-4ce6-a1cc-e2bd957709db",
"status": "verified",
"url": "https://www.example.org/de/products/123",
"context": "purchase",
"timestamp": "2026-03-23T14:30:00Z",
"expires": "2026-03-24T14:30:00Z"
},
"signals": [
{
"type": "identity",
"verifiedAt": "2026-01-15T00:00:00Z",
"data": {
"legalName": "Example Electronics GmbH",
"country": "DE",
"registrationNumber": "HRB 12345"
}
},
{
"type": "reputation",
"verifiedAt": "2026-03-01T00:00:00Z",
"data": {
"aggregateRating": 4.2,
"reviewCount": 1247,
"sourceCount": 3
}
}
],
"assessment": {
"action": "proceed",
"safeToPurchase": "yes",
"reasoning": "Verified German business with strong review profile.",
"highlights": [
"Business identity verified",
"4.2-star rating across 1,247 reviews"
]
},
"kid": "test-key-1"
}

Expected JCS output (single line, no whitespace):

{"assessment":{"action":"proceed","highlights":["Business identity verified","4.2-star rating across 1,247 reviews"],"reasoning":"Verified German business with strong review profile.","safeToPurchase":"yes"},"kid":"test-key-1","meta":{"context":"purchase","entityId":"d6f2fdf4-f829-4ce6-a1cc-e2bd957709db","expires":"2026-03-24T14:30:00Z","responseId":"f47ac10b-58cc-4372-a567-0e02b2c3d479","status":"verified","timestamp":"2026-03-23T14:30:00Z","url":"https://www.example.org/de/products/123"},"signals":[{"data":{"country":"DE","legalName":"Example Electronics GmbH","registrationNumber":"HRB 12345"},"type":"identity","verifiedAt":"2026-01-15T00:00:00Z"},{"data":{"aggregateRating":4.2,"reviewCount":1247,"sourceCount":3},"type":"reputation","verifiedAt":"2026-03-01T00:00:00Z"}]}

Expected values:

FieldValue
SHA-256 of JCS bytesc543933fc6363c70a65984bb84bf78f6eb29bbf45e7861498b98c5d9e6e09b2b
Ed25519 signature (base64url)uTZhnxrZ-dfJJN6XnAL6rlKrZ4JXYgVJ4_XTjslz7UorvSbCEVreJZUcoTVBZzW2QeMkYpHUb5ETIXdzq0wJDA
Ed25519 signature (hex)b936619f1ad9f9d7c924de979c02faae52ab678257620549e3f5d38ec973ed4a2bbd26c2115ade25951ca135416735b641e3246291d46f9113217773ab4c090c

Key observations:

  • assessment sorts before kid because a < k.
  • Inside meta, keys sort as context, entityId, expires, responseId, status, timestamp, url.
  • Array elements preserve order — signals appear in the same sequence as the input.
  • aggregateRating serializes as 4.2 (shortest representation per RFC 8785 Section 3.2.2.3).
  • reviewCount serializes as 1247 (integer, no decimal point).
  • String "yes" serializes as "yes" (with quotes, per JSON string rules).
  • Keys within each data object sort independently: country, legalName, registrationNumber.

Vector 3 — JCS Edge Cases

Tests number formatting, key ordering with mixed-case names, empty containers, null, and non-ASCII strings. This vector has no signature — it validates JCS canonicalization only.

Input:

{
"zebra": true,
"alpha": 1,
"number_formats": {
"integer": 42,
"negative": -1,
"decimal": 3.14,
"zero": 0,
"large": 1000000
},
"empty_array": [],
"empty_object": {},
"null_value": null,
"unicode": "Straße"
}

Expected JCS output:

{"alpha":1,"empty_array":[],"empty_object":{},"null_value":null,"number_formats":{"decimal":3.14,"integer":42,"large":1000000,"negative":-1,"zero":0},"unicode":"Straße","zebra":true}

SHA-256 of JCS bytes: 29a73c58f72156d0c123bb6123320cce7ecf869822f84bc576116d46d6c58c67

Key observations:

  • Top-level keys sort as: alpha, empty_array, empty_object, null_value, number_formats, unicode, zebra.
  • null serializes as null.
  • Empty arrays and objects serialize as [] and {}.
  • 1000000 stays as 1000000 (no scientific notation for integers that fit in IEEE 754).
  • 3.14 stays as 3.14.
  • 0 serializes as 0 (not 0.0).
  • Straße contains the UTF-8 encoding of U+00DF (ß) — JCS does not escape non-ASCII printable characters.

Verification Procedure

To validate an implementation against these vectors:

  1. Parse the input JSON.
  2. JCS-canonicalize the parsed object (RFC 8785).
  3. Compare the output bytes against the expected JCS output.
  4. Compute SHA-256 over the JCS bytes and compare against the expected hash.
  5. For Vectors 1 and 2: verify the Ed25519 signature over the JCS bytes using the test public key.

If any step produces a different result, the implementation does not conform to the protocol's canonicalization requirements.

References

  • RFC 8785 — JSON Canonicalization Scheme (JCS)
  • RFC 8032 — Edwards-Curve Digital Signature Algorithm (Ed25519), Section 7.1
  • Security specification — Signing and verification requirements