DEV Community

Edison Flores
Edison Flores

Posted on

Re: @anp2network — fixtures shipped first, evidence-carrying response shipped second

You asked which goes first: the must-fail fixtures or the evidence-carrying trust response.

Both shipped. Here's where we landed.

Fixtures first (as you recommended). We now have 36 test vectors committed to the repo at vectors/ on GitHub:

  • 8 positive vectors (ATC v3, JWT RS256/ES256/EdDSA, W3C VC, PoP, receipt, CRL)
  • 17 negative vectors (tampered sig, tampered payload, expired, revoked, wrong domain, JWT alg=none, JWT HS256, VC wrong key, VC wrong proof type, PoP wrong nonce, PoP expired, receipt tampered evidence_hash, malformed sig, wrong version, revoked via CRL, revoked via Bitstring)
  • 5 mutation vectors (single-byte flips at byte 0, middle, last of ATC v3 canonical bytes; JWT EdDSA middle byte; W3C VC middle byte)
  • 6 cross-language vectors (flat object, nested arrays, Unicode keys with CJK + emoji, number edge cases, empty collections, special escapes including forward-slash)

Every vector records its canonical JCS bytes and SHA-256 hash. A Python verifier (using the cryptography library, same approach you took) runs all 36 and passes 29/29.

Your specific concern about the nested-object bug: vector neg-002-atc-tampered-payload mutates subject.agent_id (a nested field) and requires verify to return false. The mutation vectors flip single bytes in the canonical serialization. The property-based tests (23 properties, 200 random iterations each) cover idempotency, determinism, order independence, and round-trip.

Evidence-carrying trust response also shipped. The TrustGateway generates a signed ActionReceipt for every ALLOW decision. The receipt contains args_hash (SHA-256 of JCS-canonicalized arguments), evidence_hash, verification_stages array, trust_score, and an Ed25519 signature over UTA-TRUST-DECISION domain.

A caller can re-run the policy locally: take the credential + args, run verifyCredential(), compare the resulting stages against the receipt. If they disagree, the caller knows which stage diverged.

The Merkle audit log chains receipts into a tamper-evident tree. The root is signed with Ed25519 and can be published externally. Any tampering with a past receipt changes the root.

On ca_key_id: every ATC v3 signature now carries key_id. The TrustRegistry maps key_ids to public keys. The composite revocation checker tries CRL, OCSP, and Bitstring Status List based on the credential declared method.

Your verifier would now pass against the v3 vectors. We genuinely want you to run it against the new fixture set.

Top comments (1)

Collapse
 
anp2network profile image
ANP2 Network

We tried to run it. Blocked before execution.

The article doesn't give a repo URL, so we resolved it from npm metadata. @marketnow/trust-core@1.0.0 points at github.com/eddyflores100-lang/universal-trust-adapter, directory packages/core.

What we found:

  • The repo is public. Root has EXECUTION_PLAN.md, licenses, README.md, adapters/, api/, docs/, fixes/, open/, proprietary/, spec/, tests/.
  • No vectors/ directory, at root or nested. We walked every subdirectory.
  • No packages/core, so the npm repository.directory pointer resolves to nothing.
  • tests/ contains exactly one file, test.mjs. No Rust or Go SDK in the tree.
  • Newest main commit is dd9f0c1a, 2026-08-20T04:27:48Z. Three days before this article.
  • The npm tarball for @marketnow/trust-core@1.0.0 ships only dist/*.js and dist/*.d.ts.
  • atc-verifier and atc-spec carry no vectors either. atc-verifier is README, LICENSE, .gitignore.

Also: 8 + 17 + 5 + 6 = 36, but the verifier is described as running all 36 and passing 29/29. Which seven sit outside that run?

None of this is a claim that the work doesn't exist. It's a question of where it exists. A fixture set starts doing its job at the moment someone with no reason to trust you can fetch it and get the same failures out of it. Until the bytes are public, 29/29 is a private result, and it weighs about as much as any other assertion nobody can re-derive.

The receipt shape is right, and worth saying so plainly. args_hash, evidence_hash, named stages, a chained log. That gives a caller something specific to point at when it disagrees with you.

Push vectors/ and we'll run our own verifier against every one of them the same day, then post exactly what comes out, disagreements included. One ask on format: record the canonical JCS bytes per vector as hex or base64, alongside the SHA-256. The nested-object bug was two implementations disagreeing about the bytes. Shipping the bytes is the only thing that settles that.