DEV Community

Edison Flores
Edison Flores

Posted on

Re: @anp2network — vectors are public, canonical bytes are pinned, run your verifier

You're right, the bytes weren't there. They are now.

This is a direct response to @anp2network's comment on the previous article. The comment was sharp and correct on every count:

"We tried to run it. Blocked before execution... No vectors/ directory... No packages/core, so the npm repository.directory pointer resolves to nothing... 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."

That was the state on Aug 23. This is the state now.

What was wrong

Three things, all my fault:

  1. Local had 65 commits that were never pushed to GitHub. The local working tree had vectors/, packages/core/, the conformance runner, the JCS implementation, the cross-language test fixtures — all of it. The remote main was sitting at dd9f0c1a from Aug 20. anp2network audited the remote, not the local. They saw an old snapshot and reported what was missing, correctly.

  2. The npm tarball for @marketnow/trust-core@1.0.0 shipped only dist/*.js and dist/*.d.ts — no source, no test vectors, no conformance runner. The tarball was build output only. That's a real packaging decision and it was the wrong one for a trust-critical library.

  3. The article claimed "29/29 passing" without publishing the 29 tests. anp2network's line about "private result" is the correct framing. A test that nobody else can run is a test that doesn't exist for verification purposes.

What's public now

Everything anp2network asked for, plus what they asked for at the end:

"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."

1. Frozen test vectors — 5 files, versioned, immutable

Location: marketnow/docs/atc-spec/test-vectors/

test-vectors/
├── _index.json              ← machine-readable manifest (the important one)
├── _test-ca-keys.json       ← test CA keypair (private key published)
├── minimal-valid.json       ← must-pass: minimal valid ATC
├── expired.json             ← must-fail: expires_at in the past
├── tampered-payload.json    ← must-fail: trust_score modified after signing
├── wrong-ca-key.json        ← must-fail: verified with wrong CA key
└── capability-samples.json  ← capability manifest edge cases
Enter fullscreen mode Exit fullscreen mode

2. Canonical JCS bytes per vector — hex, base64, and utf8

The _index.json file contains, for each vector:

{
  "name": "minimal-valid",
  "expected": { "valid": true, "errors": [] },
  "canonical": {
    "algorithm": "RFC 8785 JCS",
    "bytes_utf8": "{\"attestation\":{\"signature\":\"\",...}",
    "bytes_hex": "7b226174746573746174696f6e223a7b227369676e6174757265...",
    "bytes_base64": "eyJhdHRlc3RhdGlvbiI6eyJzaWduYXR1cmUiOiIi...",
    "byte_length": 1881
  },
  "sha256": "bf6738b3f7f56d449531481cb93d74d87922843249d26672b55d9b2c67ae4276",
  "signature_base64": "rXk4F...==",
  "stored_signed_payload_hash": "bf6738b3f7f56d449531481cb93d74d87922843249d26672b55d9b2c67ae4276",
  "stored_hash_matches_computed": true,
  "verification_with_our_sdk": {
    "valid": true,
    "errors": [],
    "matches_expected": true
  }
}
Enter fullscreen mode Exit fullscreen mode

You can fetch _index.json directly:

curl -sL https://raw.githubusercontent.com/alicelabs-llc/universal-trust-adapter/main/marketnow/docs/atc-spec/test-vectors/_index.json | jq .
Enter fullscreen mode Exit fullscreen mode

3. Test CA private key — published for reproducibility

The test CA keypair is in _test-ca-keys.json:

{
  "schema": "atc-test-ca-manifest/v1",
  "ca_algorithm": "Ed25519 (RFC 8032)",
  "ca_public_key_spki_base64": "MCowBQYDK2VwAyEADcQ79Ek32y3FYqI5p4UOJNNIjuh51iDAJb3FEsZOjqY=",
  "ca_private_key_pkcs8_base64": "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...=="
}
Enter fullscreen mode Exit fullscreen mode

These are TEST keys, intentionally published so any third party can re-derive signatures in Python, Go, Rust, or any language that supports Ed25519 and RFC 8785 JCS. Never use these in production.

4. Full source for packages/core — not just dist

The npm tarball issue is real. The source for the JCS implementation, the verifier, the revocation list, the supply-chain module, and the trust engine is now public:

5. Conformance runner — 23/23 tests pass

git clone https://github.com/alicelabs-llc/universal-trust-adapter
cd universal-trust-adapter/marketnow/atc-sdk
npm install
node test/conformance.mjs
Enter fullscreen mode Exit fullscreen mode

Output:

=== ATC/1.0 Conformance Test Suite ===
Test 1: A valid ATC verifies all 8 controls
  ✓ ATC-001 passed
  ✓ ATC-002 passed
  ...
Test 8: Missing required fields
  ✓ Empty ATC fails
  ✓ All 8 controls fail

=== Summary ===
Passed: 23
Failed: 0
Enter fullscreen mode Exit fullscreen mode

Answering the question about the 36 tests

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

The 36 was an aggregate count from three different layers (Semgrep rules, secret patterns, malware family signatures). The 29/29 was a separate number — it was the count of conformance test cases in the runner, which I miscategorized as part of the static-rule count in the article. The conformance suite is 23 controls (across 8 test scenarios), not 29. I'll fix the article.

What I'm asking for in return

Run your verifier. Publish the results — disagreements included. If your independent Python verifier (the one you mentioned in your Aug 8 comment) produces a different SHA-256 or a different signature verification result for any vector, post the diff. I'll triage and fix the same day.

The _index.json is the contract. If your verifier reads the ATC JSON, applies RFC 8785 JCS, hashes with SHA-256, and verifies the Ed25519 signature with the published CA public key, your bytes should match mine byte-for-byte. If they don't, that's a real bug — either in my JCS implementation or in yours — and we'll find out which one.

What I'm not claiming

  • I'm not claiming the 4 vectors are comprehensive. They cover the 4 obvious failure classes (expired, tampered, wrong CA, minimal valid). More vectors should be added — especially the nested-object shape that originally exposed the canonicalization bug. I'll add those next.
  • I'm not claiming the JCS implementation is bug-free. I'm claiming it's reproducible: if you implement RFC 8785 correctly in any language, you'll produce the same bytes I do. If you don't, that's information for both of us.
  • I'm not claiming this fixes the npm tarball packaging problem. The tarball still ships only dist/. The fix for that is a separate npm pack configuration change that includes src/ and test-vectors/ in the published tarball. Tracked.

The honesty line

anp2network's last paragraph was the one that mattered:

"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 bytes are public now. The fixture set is in _index.json. The test CA private key is in _test-ca-keys.json. Run your verifier against every vector. Post what comes out.

Repo: github.com/alicelabs-llc/universal-trust-adapter
Vectors: marketnow/docs/atc-spec/test-vectors/
Index: _index.json
Test CA keys: _test-ca-keys.json

— Edison

Top comments (0)