Skip to content

feat(test-vectors): APS DecisionLineageReceipt for ku_4b3f7c2a9d8e1f05#7

Open
aeoess wants to merge 1 commit intoVeritasActa:feat/ku-test-vectorsfrom
aeoess:contrib/aps-receipt-ku-4b3f7c
Open

feat(test-vectors): APS DecisionLineageReceipt for ku_4b3f7c2a9d8e1f05#7
aeoess wants to merge 1 commit intoVeritasActa:feat/ku-test-vectorsfrom
aeoess:contrib/aps-receipt-ku-4b3f7c

Conversation

@aeoess
Copy link
Copy Markdown

@aeoess aeoess commented Apr 18, 2026

Summary

Drops a signed APS DecisionLineageReceipt into external_receipts.aps.receipt
for ku_id=ku_4b3f7c2a9d8e1f05, completing the slot left open in #6.

Refs #2 (cross-verify commitment) and #6 (KU test vectors).

The receipt commits to the bundle by recording, for each entry in
bundle.receipts, a contributingSources[i].accessReceiptId of the form
sha256:<jcs-canonical-sha256>. The 10 hashes match the bundle exactly,
including the chain values your own previousReceiptHash fields already
publish (e.g. sha256:2b06eb3385bcfa… for receipt 1).

The signing key is a deterministic test key (NOT an AEOESS production
issuer), derived as sha256("aps:veritasacta:ku-cross-verify:v1"). Public
key + seed note are inlined in external_receipts.aps.signing_key so anyone
can re-derive and re-verify offline. Reference signer:
interop/scripts/sign-va-ku-receipt.ts
in agent-passport-system.

Verification

$ npx @veritasacta/verify test-vectors/cross-verify-bundle.json --bundle
✓ Bundle: VALID
  Total:    10
  Passed:   10
  Failed:   0

APS-side independent check (Ed25519 sig + 10/10 cross-layer hashes match):

APS Ed25519 signature valid: true
Cross-layer integrity (10/10 hashes match bundle): true

Tamper test

Flip a single field in receipt 9 (payload.synthesis.synthesis_confidence
0.68 → 0.99) and re-verify:

  • @veritasacta/verify: Receipt 9: invalid_signature — the round chain
    detects the change exactly where it happened.
  • APS verifier: APS Ed25519 signature valid: true,
    Cross-layer integrity (9/10 hashes match bundle): false
    contributingSources[8].accessReceiptId no longer matches the recomputed
    hash. APS's signature stays valid (proving APS isn't the tamperer) while
    the bundle is observably stale relative to APS's attestation.

This is the cross-layer integrity property promised in #2: tampering
invalidates both the VeritasActa Ed25519 chain and the APS attestation,
without requiring APS to re-sign anything per receipt.

Scope

  • Modifies only test-vectors/cross-verify-bundle.json — populates the
    pre-existing external_receipts.aps slot, leaves all 10 KU receipts and
    signing keys byte-for-byte unchanged.
  • No other test vectors or repo files touched.

cc @tomjwxf — happy to adjust the receipt's shape if you'd prefer a
different commitment scheme (e.g. Merkle root over receipt hashes instead
of per-receipt entries).

…eipts.aps.receipt slot for ku_4b3f7c2a9d8e1f05
Copy link
Copy Markdown
Contributor

@tomjwxf tomjwxf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for populating the APS slot. Cross-verifying APS DecisionLineageReceipts against @veritasacta/verify is a meaningful first in the implementation matrix, and the cross-layer integrity demo (contributingSources[i].accessReceiptId binding APS receipts to the Ed25519 chain via hash) is the concrete shape the IETF draft has been asserting without fixtures to point at. Good work.

Want to hold on merging until the signing_key placement is adjusted though. Current structure inlines the public key at external_receipts.aps.signing_key, which is the exact pattern surfaced as a spec gap by @desiorac on GetBindu #459 recently. draft-02 (going out later this week) adds a normative "MUST NOT accept a verification key transported inside the receipt unless that key is independently anchored" requirement in Security Considerations, @veritasacta/verify 0.4.0 will enforce it, and a matching negative conformance vector lands in ScopeBlind/agent-governance-testvectors. The canonical verify repo shipping a fixture that relies on the embedded-key convenience would teach the wrong lesson right as the spec tightens.

Two restructure options that keep the educational value:

Option A (probably the one you want): Move the key to a sidecar JWKS at test-vectors/keys/aps-ku-cross-verify.jwks and reference via a verification_key_ref field in the bundle. Verifier invocation becomes:

npx @veritasacta/verify test-vectors/cross-verify-bundle.json \
    --bundle --jwks test-vectors/keys/aps-ku-cross-verify.jwks

Single extra JSON file, establishes the pattern future fixtures copy.

Option B: Leave a SHA-256 fingerprint of the key in the receipt ("this receipt claims to be signed by the key with this fingerprint") but require the verifier to resolve the full key from a known location. Matches how SSH known_hosts works. More involved restructure.

Option A is the minimal change. Happy to push a suggested-change commit to this branch with the sidecar JWKS + verifier-invocation update if easier than doing it yourself. Let me know which option you prefer and I'll either draft it or wait for you.

Everything else in the PR is clean and ready to land the moment the key placement is resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants