# AIR v1 Golden Test Vectors

**Status:** v1.0 FROZEN
**Date:** 2026-02-25

## Purpose

These vectors provide byte-stable, deterministic test data for AIR v1 conformance testing.
Any implementation that can parse, verify, and validate these vectors is compatible with the
reference implementation.

## Signing Key

All vectors use a deterministic Ed25519 keypair derived from seed `[0x2A; 32]`:

| Field | Hex |
|-------|-----|
| Seed | `2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a` |
| Public key | `197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61` |

## Valid Vectors

| File | Description |
|------|-------------|
| `valid/v1-nitro-no-nonce.json` | Nitro measurements, no eat_nonce. Canonical golden vector. |
| `valid/v1-tdx-with-nonce.json` | TDX measurements, with eat_nonce. Tests nonce binding + TDX variant. |

## Invalid Vectors

### Structural failures (Layers 1-3)

| File | Expected Failure | Layer |
|------|-----------------|-------|
| `invalid/v1-wrong-key.json` | SIG_FAILED | 2 (crypto) |
| `invalid/v1-wrong-alg.json` | BAD_ALG | 1 (parse) |
| `invalid/v1-zero-model-hash.json` | ZERO_MODEL_HASH | 3 (claim validation) |
| `invalid/v1-bad-measurement-length.json` | BAD_MEASUREMENT_LENGTH | 3 (claim validation) |

### Policy failures (Layer 4)

These vectors contain structurally valid receipts. Failure occurs when
the verifier's `AirVerifyPolicy` contains constraints that the receipt
does not satisfy. Each vector includes a `verify_policy` field specifying
the policy that triggers the failure.

| File | Expected Failure | Policy Field |
|------|-----------------|--------------|
| `invalid/v1-nonce-mismatch.json` | NONCE_MISMATCH | `expected_nonce_hex` |
| `invalid/v1-model-hash-mismatch.json` | MODEL_HASH_MISMATCH | `expected_model_hash_hex` |
| `invalid/v1-platform-mismatch.json` | PLATFORM_MISMATCH | `expected_platform` |
| `invalid/v1-stale-iat.json` | TIMESTAMP_STALE | `max_age_secs` |

## JSON Schema

Each vector file contains:

```json
{
  "name": "vector-name",
  "description": "...",
  "receipt_hex": "d284...",           // Full COSE_Sign1 tagged bytes
  "payload_hex": "b0...",             // CWT claims (CBOR map) — valid vectors only
  "public_key_hex": "197f...",        // Ed25519 verifying key
  "claims": { ... },                  // Human-readable claim values — valid vectors only
  "expected_verification": { ... },   // Expected layer outcomes — valid vectors
  "expected_failure": { ... },        // Expected failure code — invalid vectors
  "verify_policy": { ... }            // Policy overrides — policy failure vectors only
}
```

### `verify_policy` Fields

For policy-failure vectors, the `verify_policy` object specifies the
policy parameters that cause the failure:

| Field | Type | Description |
|-------|------|-------------|
| `expected_nonce_hex` | hex string | Expected `eat_nonce` value |
| `expected_model_hash_hex` | hex string | Expected `model_hash` (32 bytes) |
| `expected_platform` | string | Expected `measurement_type` |
| `max_age_secs` | integer | Maximum receipt age in seconds |

## Using Vectors

### Rust (reference implementation)

```rust
let receipt = hex::decode(vector.receipt_hex).unwrap();
let pubkey_bytes = hex::decode(vector.public_key_hex).unwrap();
let pubkey = ed25519_dalek::VerifyingKey::from_bytes(
    &pubkey_bytes.try_into().unwrap()
).unwrap();
let result = verify_air_v1_receipt(&receipt, &pubkey, &policy);
assert!(result.verified); // or assert failure code
```

### Other languages

1. Decode `receipt_hex` to bytes
2. Parse as COSE_Sign1 (CBOR tag 18)
3. Verify Ed25519 signature over Sig_structure1
4. Decode payload as CBOR map
5. Validate claims per AIR v1 spec
6. Apply policy constraints from `verify_policy` (if present)

## Regeneration

Vectors are generated by the `golden_vectors` and `structural_invalid_vectors`
tests in `common/src/air_receipt.rs`. If the encoding changes, the test will
fail — update vectors only after spec review.

## Post-Hardening Confirmation (2026-02-28)

Golden vectors regenerated after Tier 1+2 parse hardening (commit `0da2611`).
All `receipt_hex` values are **byte-identical** to the v1.0 frozen vectors.
The hardening changes (size limits, duplicate key checks, text bounds, iat≠0,
TDX+pcr8 cross-check) affect only rejection paths and do not alter encoding.
