aere-quantum/conformance/genereaza-vectori.mjs

663 lines
98 KiB
JavaScript

#!/usr/bin/env node
// genereaza-vectori.mjs: the conformance vectors, DERIVED from the producers and from evidence already recorded, never typed by hand.
//
// node genereaza-vectori.mjs rewrites vectori/ from: the producers run on fixed inputs (the AIP-23 kinds), the evidence
// recorded on testnet 28001 beside the products (a receipt, five market timelines, a notarized
// dataset commitment), and surse-proaspete.json (what needs a key, randomness or the chain)
// node genereaza-vectori.mjs --verifica regenerates in memory and compares with vectori/ byte for byte: LA ZI (0) or DIFERIT (1)
// node genereaza-vectori.mjs --proaspat completes surse-proaspete.json with what is MISSING from it (what is there stays, so the
// vectors derived from it stay): keys made and discarded here sign a tree head (ML-DSA-65)
// and its classical impostor (Ed25519), a random envelope nobody notarized, a small dataset
// (random salts), the presentations of one identity credential with their forged siblings
// (six hybrid key pairs), and the transaction of the recorded receipt READ from testnet 28001 (two
// eth_ calls; nothing is sent). With --tot everything is made anew
//
// A vector is { artifact, input, expected: { verdict, failed, levels } }. An INVALID vector names its `base` (a vector that is not
// INVALID) and its `mutation`: ONE operation (set, remove, add at one JSON path) applied to the base input, so that it differs from the
// base in exactly one place and must be refused for exactly the rules in `expected.failed`. Where the rule sits under a hash (an amount
// under the instruction hash, an order under an index root) one place is not reachable: the mutation is then made at the PRODUCER
// (`mutation.producer`), the commitments above it recomputed, and `mutation.changed` lists every path that moved.
// `exercises` are the rules an implementation must be able to judge to be scored on the vector; `requires: ['rpc-28001']` marks the
// vectors that need the testnet endpoint (run only with --online).
import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import crypto from 'node:crypto'; import { fileURLToPath } from 'node:url';
import { buildProof, KINDS } from '../proof-kinds/proof-kinds.mjs';
import { buildProofOfAi } from '../proof-of-ai/proof-of-ai.mjs';
import { definePolicy, checkAction, decisionEnvelope } from '../agents/agent-policy.mjs';
import { capDeArbore, dovadaIncludere, dovadaConsistenta } from '../verify-layer/jurnal-arbore.mjs';
import { hashIntrare, semneazaCap } from '../verify-layer/sidecar.mjs';
import { merkleTree } from '../verify-layer/arbore-merkle.mjs';
import * as RISC from '../payments/risc.mjs';
import * as BAZA from '../verifiable-data/baza.mjs';
import { newAgentIdentity, openLedger, agentIdFromKey, sessionId, canonical as canonicLedger } from '../agents/agent-ledger.mjs';
import { construieste as lantAI } from '../ai-trust/lant-de-incredere.mjs';
import * as ID from '../identity/identity.mjs';
import { hartaPublica, LEVELS } from './reguli.mjs';
const AICI = path.dirname(fileURLToPath(import.meta.url));
const DIR = path.join(AICI, 'vectori'); const PROASPETE = path.join(AICI, 'surse-proaspete.json');
const DOV = { chitanta: new URL('../payments/dovezi/chitanta-28001-2026-10-02T1716Z.json', import.meta.url), piata: new URL('../market-settlement/dovezi/piata-28001-2026-10-02T1652Z.json', import.meta.url),
date: new URL('../verifiable-data/dovezi/notarizare-28001-2026-10-02T0820Z.json', import.meta.url),
lantAI: new URL('../ai-trust/dovezi/lant-28001-2026-10-02T0519Z.json', import.meta.url) };
const citeste = (u) => JSON.parse(fs.readFileSync(fileURLToPath(u), 'utf8'));
const clona = (x) => JSON.parse(JSON.stringify(x));
const sha256 = (b) => '0x' + crypto.createHash('sha256').update(b).digest('hex');
const HARTA = hartaPublica();
const RPC_28001 = process.env.AERE_CONFORMANCE_RPC_28001 || 'https://testnet-rpc.aere.network';
// ---------- one operation at one path ----------
export function aplica(input, op) {
const c = clona(input); let o = c; const p = op.path;
for (const k of p.slice(0, -1)) { if (o == null || !(k in Object(o))) throw new Error('mutation path not in the base: ' + p.join('.')); o = o[k]; }
const k = p[p.length - 1];
if (op.op === 'set') { if (!(k in Object(o))) throw new Error('set: nothing at ' + p.join('.')); o[k] = clona(op.value); }
else if (op.op === 'add') { if (k in Object(o)) throw new Error('add: something already at ' + p.join('.')); o[k] = clona(op.value); }
else if (op.op === 'remove') { if (!(k in Object(o))) throw new Error('remove: nothing at ' + p.join('.')); if (Array.isArray(o)) o.splice(k, 1); else delete o[k]; }
else throw new Error('unknown op ' + op.op);
return c;
}
const nivele = (failed, extra = {}) => {
const n = Object.fromEntries(LEVELS.map((l) => [l, 'NOT_MEASURED'])); n.integrity = 'PASSED'; Object.assign(n, extra);
for (const r of failed) { if (!HARTA[r]) throw new Error('a vector expects an unknown rule: ' + r); n[HARTA[r].level] = 'FAILED'; }
return n;
};
const V = []; // the vectors, in order
function valid(id, artifact, title, source, input, { exercises, requires = [], verdict = 'VALID', levels = {}, base = null, mutation = null }) {
V.push({ v: 1, kind: 'aere-conformance-vector', id, artifact, title, source, requires, exercises: [...exercises].sort(), base, mutation, input, expected: { verdict, failed: [], levels: nivele([], levels) } });
return input;
}
function invalid(id, title, bazaId, op, failed, { levels = {}, exercises = null, requires = null, producer = null } = {}) {
const b = V.find((x) => x.id === bazaId); if (!b) throw new Error('no base ' + bazaId); if (b.expected.verdict === 'INVALID') throw new Error('the base of ' + id + ' is itself INVALID');
const input = producer ? producer.input : aplica(b.input, op);
const mutation = producer ? { producer: producer.note, changed: producer.changed } : op;
V.push({ v: 1, kind: 'aere-conformance-vector', id, artifact: b.artifact, title, source: 'derived from ' + bazaId, requires: requires || b.requires, exercises: (exercises || b.exercises).slice().sort(), base: bazaId, mutation, input,
expected: { verdict: 'INVALID', failed: [...failed].sort(), levels: nivele(failed, { ...b.expected.levels, ...levels }) } });
}
// ---------- the fresh sources: a key, randomness, the chain ----------
async function proaspat(tot) {
// what is already in surse-proaspete.json STAYS (the vectors derived from it stay byte for byte); only what is missing is made.
// --tot remakes everything (other keys, other salts: every vector derived from the fresh sources changes).
const P = !tot && fs.existsSync(PROASPETE) ? JSON.parse(fs.readFileSync(PROASPETE, 'utf8')) : { v: 1, kind: 'aere-conformance-fresh-sources', at: new Date().toISOString() };
const AT = new Date().toISOString(); const facute = []; const INT = intrariKinds();
if (!P.signedHead) { // a signed tree head: three envelopes in a hash-chained log, the head signed with an ML-DSA-65 key that exists only in this call
let prev = '0x' + '00'.repeat(32);
const jurnal = ['data', 'execution', 'time'].map((k, seq) => { const proof = buildProof(k, INT[k]); const hash = hashIntrare(seq, prev, proof); const e = { seq, prev, proof, hash }; prev = hash; return e; });
const { privateKey } = crypto.generateKeyPairSync('ml-dsa-65');
P.signedHead = capDeArbore(jurnal, { host: 'conformance', createdAt: AT, signKeyPem: privateKey.export({ type: 'pkcs8', format: 'pem' }) }); facute.push('signedHead');
}
if (!P.classicalHead) { // the same head "signed" by a signer that used a CLASSICAL key and declared the post-quantum scheme (the key exists only in this call)
const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519'); const h = clona(P.signedHead);
h.signature = { scheme: 'ml-dsa-65', publicKey: publicKey.export({ type: 'spki', format: 'der' }).toString('base64'), signature: crypto.sign(null, Buffer.from(JSON.stringify(h.statement), 'utf8'), privateKey).toString('base64') };
P.classicalHead = h; facute.push('classicalHead');
}
if (!P.fresh) { P.fresh = buildProof('data', { name: 'conformance-fresh', content: crypto.randomBytes(32).toString('hex'), createdAt: AT }); facute.push('fresh'); } // an envelope nobody notarized
if (!P.receiptTx) { // the transaction of the recorded receipt, read from the chain
const ins = citeste(DOV.chitanta).instruction;
const rpc = async (method, params) => { const r = await fetch(RPC_28001, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), signal: AbortSignal.timeout(20000) }); if (!r.ok) throw new Error(method + ': HTTP ' + r.status); const j = await r.json(); if (j.error || !j.result) throw new Error(method + ': ' + JSON.stringify(j.error || 'no result')); return j.result; };
const t = await rpc('eth_getTransactionByHash', [ins.txHash]); const rc = await rpc('eth_getTransactionReceipt', [ins.txHash]);
P.receiptTx = { chainId: 28001, readAt: AT, tx: { from: t.from, to: t.to, value: t.value, blockHash: t.blockHash }, txReceipt: { status: rc.status, blockHash: rc.blockHash } }; facute.push('receiptTx');
}
if (!P.dataset) { // a small dataset: 12 records committed as version 1, 4 more as version 2
const T = fs.mkdtempSync(path.join(os.tmpdir(), 'aere-conf-set-'));
try {
const TARI = ['RO', 'DE', 'FR', 'ES']; const rec = (n, de = 0) => Array.from({ length: n }, (_, j) => { const k = de + j; return { id: 'r' + k, country: TARI[k % 4], age: 20 + ((k * 7) % 40), email: 'u' + k + '@example.test', note: 'undisclosed-' + k }; });
const db = BAZA.creeaza(path.join(T, 'set'), { name: 'conformance', indexes: ['country', 'age'] });
BAZA.adauga(db, rec(12)); BAZA.angajeaza(db, { createdAt: '2026-10-03T00:00:00.000Z' }); BAZA.adauga(db, rec(4, 12)); BAZA.angajeaza(db, { createdAt: '2026-10-03T00:01:00.000Z' });
const c1 = BAZA.versiune(db, 1), c2 = BAZA.versiune(db, 2);
const cerute = []; const seed = 'conformance-sample'; const k = 4;
await BAZA.esantioneaza({ url: 'vector://served', commitment: c2, k, seed, ia: async (u) => { cerute.push(Number(u.split('/').pop())); return null; } });
P.dataset = { older: c1, newer: c2, record: BAZA.dovadaInregistrare(db, 2, 5, { fields: ['country', 'age'] }), answer: BAZA.interogheaza(db, 2, { field: 'age', from: 30, to: 45, fields: ['country'] }),
consistency: BAZA.dovadaConsistenta(db, 1, 2), sample: { k, seed, served: Object.fromEntries(cerute.map((i) => [String(i), BAZA.dovadaInregistrare(db, 2, i, { fields: ['country'] })])) } };
facute.push('dataset');
} finally { fs.rmSync(T, { recursive: true, force: true }); }
}
for (const [nume, face] of Object.entries(PROASPETE_IN_PLUS)) if (!P[nume]) { P[nume] = await face(P, AT); facute.push(nume); }
fs.writeFileSync(PROASPETE, JSON.stringify(P, null, 1) + '\n');
console.log(path.basename(PROASPETE) + ': ' + (facute.length ? 'made now: ' + facute.join(', ') : 'nothing was missing') + '; kept: ' + Object.keys(P).filter((k) => !['v', 'kind', 'at'].includes(k) && !facute.includes(k)).join(', '));
}
/** more fresh sources, each made once: name -> async (P, AT) => value. The sections of the vectors below add theirs here. */
/** the audit log of the vectors: six envelopes of the fixed inputs in a hash chain (no key, no randomness: remade the same every time) */
function jurnalAudit(strica = null) {
const INT = intrariKinds(); let prev = '0x' + '00'.repeat(32);
return ['data', 'execution', 'time', 'identity', 'location', 'device'].map((k, seq) => { const proof = buildProof(k, INT[k]); if (strica) strica(seq, proof); const hash = hashIntrare(seq, prev, proof); const e = { seq, prev, proof, hash }; prev = hash; return e; });
}
/** the attested head of the first `count` entries, in the form the sidecar's attest-head writes */
function capAudit(log, count) {
const statement = { v: 1, kind: 'aere-audit-head', host: 'conformance', count, head: count ? log[count - 1].hash : '0x' + '00'.repeat(32), createdAt: '2026-10-03T00:00:00Z' };
return { v: 1, kind: 'aere-audit-head-attestation', statement, statementHash: sha256(Buffer.from(JSON.stringify(statement), 'utf8')) };
}
const PROASPETE_IN_PLUS = {
// the ledger of ONE agent (its ML-DSA-65 key exists only in this call): four entries written through the ledger; the same ledger
// with its fourth entry written by an agent that signs what the ledger would not write (an empty approvals list, a false decision,
// a revocation entry without a revocation); and a ledger whose "agent identity" is a classical key
agentLedger: async () => {
const t0 = Math.floor(Date.now() / 1000) - 3600; const sha = (s) => crypto.createHash('sha256').update(Buffer.from(s, 'utf8')).digest('hex');
const identity = newAgentIdentity(); const { policy, policyHash } = definePolicy({ agentId: identity.agentId, spend: { amount: '100', windowSeconds: 3600 }, recipients: ['0xbbbb'], tools: ['retrieval'] });
const L = openLedger({ identity, policy, policyHash, now: () => t0 });
L.record({ kind: 'tool', tool: 'retrieval' }); L.record({ kind: 'payment', to: '0xbbbb', amount: '40' }); L.record({ kind: 'payment', to: '0xbbbb', amount: '70' });
const trei = L.export(); L.record({ kind: 'tool', tool: 'retrieval' }); const base = L.export();
const intrare = (key, prev, seq, body) => { const b = { ...body, seq }; const signature = crypto.sign(null, Buffer.from(`${seq}|${prev}|${canonicLedger(b)}`, 'utf8'), key).toString('base64'); return { seq, prev, body: b, signature, hash: sha(`${seq}|${prev}|${canonicLedger(b)}|${signature}`) }; };
const antet = { v: 2, agentId: identity.agentId, policyHash, session: trei.session }; const prev3 = trei.entries[2].hash;
const cu = (body) => ({ ...trei, entries: [...trei.entries, intrare(identity.privateKey, prev3, 3, { ...antet, at: t0, ...body })] });
const unealta = { kind: 'tool', tool: 'retrieval', at: t0 };
const cl = crypto.generateKeyPairSync('ed25519'); const idCl = agentIdFromKey(cl.publicKey); const pc = definePolicy({ agentId: idCl, tools: ['retrieval'] }); const sesCl = sessionId(idCl, pc.policyHash);
const clasic = { version: base.version, agentId: idCl, publicKeyPem: cl.publicKey.export({ type: 'spki', format: 'pem' }), policyHash: pc.policyHash, session: sesCl,
entries: [intrare(cl.privateKey, '0'.repeat(64), 0, { v: 2, agentId: idCl, policyHash: pc.policyHash, session: sesCl, at: t0, action: unealta, decision: { allowed: true, reason: 'tool allowed' }, provenance: null })] };
return { t0, policy, ledger: base,
approvalsEmpty: cu({ action: unealta, decision: { allowed: true, reason: 'tool allowed' }, provenance: null, approvals: [] }),
falseDecision: cu({ action: { kind: 'payment', to: '0xbbbb', amount: '10', at: t0 }, decision: { allowed: false, reason: 'refused by the agent' }, provenance: null }),
revocationWithout: cu({ action: { kind: 'revocation', revokedAt: t0, at: t0 }, decision: { allowed: false, reason: 'revocation' }, provenance: null }),
classical: { ledger: clasic, policy: pc.policy } };
},
// the head of the audit log signed by its operator (ML-DSA-65), by a classical key that declares ml-dsa-65, and the public key of
// another operator; the private keys exist only in this call
auditHead: async () => {
const cap = capAudit(jurnalAudit(), 4); const op = crypto.generateKeyPairSync('ml-dsa-65'), alt = crypto.generateKeyPairSync('ml-dsa-65'), cl = crypto.generateKeyPairSync('ed25519');
const pem = (k) => k.export({ type: 'spki', format: 'pem' });
const clasic = { ...cap, signature: { scheme: 'ml-dsa-65', publicKey: cl.publicKey.export({ type: 'spki', format: 'der' }).toString('base64'), signature: crypto.sign(null, Buffer.from(JSON.stringify(cap.statement), 'utf8'), cl.privateKey).toString('base64') } };
return { signed: semneazaCap(cap, op.privateKey.export({ type: 'pkcs8', format: 'pem' })), signerPem: pem(op.publicKey), otherSignerPem: pem(alt.publicKey), classical: clasic };
},
// three trust chains of ONE agent (its ML-DSA-65 key exists only in this call), without model attestation and runtime record:
// an action the policy allows; the same action under a policy that does not list the tool (the ledger records the refusal);
// an output dated a long time before its ledger entry
aiTrust: async () => {
const t1 = Math.floor(Date.now() / 1000) - 3600, iso = (t) => new Date(t * 1000).toISOString(); const identity = newAgentIdentity();
const lant = (tools, outAt) => { const { policy, policyHash } = definePolicy({ agentId: identity.agentId, tools }); const ledger = openLedger({ identity, policy, policyHash, now: () => t1 });
const proofOfAi = buildProofOfAi({ model: { name: 'example-model', version: '1.0' }, prompt: 'summarise document X', input: 'document X', output: 'a summary of document X', tools: ['model:example-model'], agentId: identity.agentId, requester: 'tester', createdAt: iso(outAt) });
ledger.record({ kind: 'tool', tool: 'model:example-model', args: { promptHash: proofOfAi.statement.promptHash } }, { provenance: proofOfAi, at: t1 });
return lantAI({ ledger: ledger.export(), policy: { policy, policyHash }, proofOfAi, createdAt: iso(t1) }); };
return { allowed: lant(['model:example-model'], t1), refused: lant(['model:another-model'], t1), lateEntry: lant(['model:example-model'], t1 - 7200) };
},
// presentations of ONE credential (issuer, holder, a phone, a session key, a stranger and an impostor issuer: six hybrid key pairs
// that exist only in this call), made by the identity producers (issueCredential, createStatusList, delegate, revokeDelegation,
// present) at a fixed time, with the verifier's audience, nonce and clock; and the forged siblings that only a key holder can make:
// a statement changed and signed again by the issuer, the holder or a delegate, with the published formulas (the purpose-separated
// hybrid signature over the canonical statement; the sha256 of the canonical JSON as the hash)
identity: async () => {
const T0 = Math.floor(Date.now() / 1000) * 1000 - 3600000, zi = 86400; const at = (s) => new Date(T0 + s * 1000).toISOString(), la = (s) => new Date(T0 + s * 1000);
const [iss, hol, phone, sess, strain, imp] = Array.from({ length: 6 }, () => ID.generateKeys());
const AUD = 'https://verifier.example', NONCE = 'n-' + crypto.randomBytes(8).toString('hex'), LID = 'https://issuer.example/status/1', hashOf = ID.credentialHash;
const afirmatii = { name: 'Ada Example', age_over_18: true, member_since: '2020', employer: 'Example Ltd' }, DZ = ['name', 'age_over_18', 'member_since'];
const schimba = (c) => (c[0] === 'A' ? 'B' : 'A') + c.slice(1);
const emite = (o = {}) => ID.issueCredential({ issuer: iss, holder: hol.public, type: 'ExampleMembership', claims: afirmatii, disclosable: DZ, validFrom: at(-zi), validUntil: at(1000 * zi), status: { list: LID, index: 42 }, decoys: 2, now: la(0), ...o });
const { credential, disclosures } = emite();
const cuCred = (c, dz = disclosures, o = {}) => ID.present({ credential: c, disclosures: dz, reveal: ['age_over_18', 'member_since'], presenter: hol, audience: AUD, nonce: NONCE, now: la(60), ...o });
const resemneaza = (p, k, f) => { const q = clona(p); f(q); q.signature = ID.signText('presentation', ID.canonical(q.binding), k); return q; };
const reemite = (c, k, f) => { const st = clona(c.statement); f(st); return { statement: st, signature: ID.signText('credential', ID.canonical(st), k) }; };
const dzv = (nume, val, octeti = 16) => Buffer.from(JSON.stringify([crypto.randomBytes(octeti).toString('base64url'), nume, val]), 'utf8').toString('base64url');
const direct = cuCred(credential); const cuDezvaluiri = (l) => resemneaza(direct, hol, (q) => { q.disclosures = l; q.binding.disclosuresHash = hashOf(l); });
const lista = (o = {}) => ID.createStatusList({ issuer: iss, id: LID, validFrom: at(-3600), validUntil: at(zi), now: la(0), ...o });
const curata = lista(); const fals = 'aere-id:' + '11'.repeat(20); const altId = 'urn:uuid:' + ['00000000', '0000', '4000', '8000', '000000000000'].join('-'); // the id of a credential that is not this one
// the same claims from an issuer that names no status list (the impostor, and the issuer with a classical key)
const faraStare = ID.issueCredential({ issuer: imp, holder: hol.public, type: 'ExampleMembership', claims: afirmatii, disclosable: DZ, validFrom: at(-zi), validUntil: at(1000 * zi), now: la(0) });
const clasic = (() => { const a = crypto.generateKeyPairSync('ed25519'), b = crypto.generateKeyPairSync('ed25519'); const spki = (k) => k.publicKey.export({ type: 'spki', format: 'der' }).toString('base64');
const pub = { alg: ID.ALG, ed25519: spki(a), mldsa65: spki(b) }; const id = 'aere-id:' + crypto.createHash('sha256').update(Buffer.from(ID.canonical(pub), 'utf8')).digest('hex').slice(0, 40);
const st = clona(faraStare.credential.statement); st.issuer = { id, keys: pub }; const m = Buffer.from('aere-identity/v1/credential\n' + ID.canonical(st), 'utf8');
const c = { statement: st, signature: { alg: ID.ALG, ed25519: crypto.sign(null, m, a.privateKey).toString('base64'), mldsa65: crypto.sign(null, m, b.privateKey).toString('base64') } };
return { issuerId: id, presentation: cuCred(c, faraStare.disclosures) }; })();
const listaNecitibila = (() => { const st = clona(curata.statement); st.encodedList = Buffer.from('not gzip', 'utf8').toString('base64url'); return { statement: st, signature: ID.signText('status-list', ID.canonical(st), iss) }; })();
const inClar = (() => { const enc = dzv('employer', 'Another Ltd'); const c = reemite(credential, iss, (st) => { st.sd = [...st.sd, ID.digestOf(enc)].sort(); });
return resemneaza(cuCred(c), hol, (q) => { q.disclosures = [...q.disclosures, enc]; q.binding.disclosuresHash = hashOf(q.disclosures); }); })();
const expirat = emite({ validFrom: at(-3 * zi), validUntil: at(-zi) }), inca = emite({ validFrom: at(zi), validUntil: at(2 * zi) });
// delegation: the holder to a phone, the phone to a session key of ten minutes
// the scope of a link: which credential ids, which disclosable claims, which audiences (built by position: the field is named in one place)
const scopul = (iduri, afirm, publicuri) => Object.fromEntries([['credentials', iduri], ['claims', afirm], ['audiences', publicuri]]);
const scop = scopul([credential.statement.id], ['age_over_18', 'member_since'], [AUD]), ingust = { ...scop, claims: ['age_over_18'] };
const d1 = ID.delegate({ from: hol, to: phone.public, scope: scop, notBefore: at(0), notAfter: at(zi), maxDepth: 1, now: la(0) });
const d2 = ID.delegate({ from: phone, to: sess.public, scope: ingust, notBefore: at(30), notAfter: at(600), maxDepth: 0, parent: d1, now: la(30) });
const prezD = (lant, cheie, o = {}) => ID.present({ credential, disclosures, reveal: ['age_over_18'], presenter: cheie, delegations: lant, audience: AUD, nonce: NONCE, now: la(60), ...o });
const una = (o = {}) => ID.delegate({ from: hol, to: phone.public, scope: scop, notBefore: at(0), notAfter: at(zi), maxDepth: 0, now: la(0), ...o });
const veriga = (k, st0, f) => { const st = clona(st0); f(st); return { statement: st, signature: ID.signText('delegation', ID.canonical(st), k) }; };
const delegat = prezD([d1, d2], sess); const d1z = una();
const lung = (() => { const chei = [phone, sess]; let de = hol; const l = []; for (let i = 0; i < 9; i++) { const catre = chei[i % 2]; l.push(ID.delegate({ from: de, to: catre.public, scope: scop, notBefore: at(0), notAfter: at(zi), maxDepth: 0, now: la(0) })); de = catre; } return prezD(l, de); })();
const semnaturaVerigii = (() => { const d = clona(una()); d.signature.mldsa65 = schimba(d.signature.mldsa65); return prezD([d], phone); })();
return { at: at(0), audience: AUD, nonce: NONCE, now: at(65), later: at(3665), muchLater: at(4000 * zi), trusted: [iss.id], strangerId: strain.id,
lists: { clean: curata, revoked: lista({ revoked: [42] }), unreadable: listaNecitibila, short: lista({ size: 8 }), otherIssuer: ID.createStatusList({ issuer: imp, id: LID, revoked: [42], validFrom: at(-3600), validUntil: at(zi), now: la(0) }), expired: lista({ revoked: [42], validFrom: at(-2 * zi), validUntil: at(-zi) }) },
undisclosed: disclosures.find((e) => ID.decodeDisclosure(e).name === 'name'),
direct, delegated: delegat,
revocations: { byHolder: ID.revokeDelegation({ by: hol, delegation: d1, at: at(10), now: la(10) }), byGiver: ID.revokeDelegation({ by: phone, delegation: d2, at: at(40), now: la(40) }),
byStranger: ID.revokeDelegation({ by: strain, delegation: d1, at: at(10), now: la(10) }), inTheFuture: ID.revokeDelegation({ by: hol, delegation: d1, at: at(zi), now: la(10) }) },
forged: {
issuerImpostor: cuCred(reemite(faraStare.credential, imp, (st) => { st.issuer.id = iss.id; }), faraStare.disclosures),
issuerClassicalKey: clasic,
holderId: resemneaza(cuCred(reemite(credential, iss, (st) => { st.holder.id = fals; })), hol, (q) => { q.binding.presenter.id = fals; }),
credentialSignatureMlDsa: cuCred((() => { const c = clona(credential); c.signature.mldsa65 = schimba(c.signature.mldsa65); return c; })()),
credentialSignatureEd25519: cuCred((() => { const c = clona(credential); c.signature.ed25519 = schimba(c.signature.ed25519); return c; })()),
claimEdited: cuCred((() => { const c = clona(credential); c.statement.claims.employer = 'Another Ltd'; return c; })()),
expired: cuCred(expirat.credential, expirat.disclosures), notYetValid: cuCred(inca.credential, inca.disclosures),
sdTwice: cuCred(reemite(credential, iss, (st) => { st.sd = [...st.sd, st.sd[0]].sort(); })),
disclosureShortSalt: cuDezvaluiri([...direct.disclosures, dzv('nickname', 'x', 8)]),
disclosureFabricated: cuDezvaluiri([...direct.disclosures, dzv('age_over_21', true)]),
disclosureTwice: cuDezvaluiri([direct.disclosures[0], direct.disclosures[0], direct.disclosures[1]]),
disclosureOverPlain: inClar,
claimName: cuCred(reemite(credential, iss, (st) => { st.claims['bad name'] = 'x'; })),
otherCredential: resemneaza(direct, hol, (q) => { q.binding.credentialHash = hashOf(emite().credential); }),
stranger: cuCred(credential, disclosures, { presenter: strain }),
createdAt: resemneaza(direct, hol, (q) => { q.binding.createdAt = 'yesterday'; }),
chainUnsigned: resemneaza(delegat, sess, (q) => { q.binding.delegations = []; }),
chainNine: lung,
linkForm: prezD([veriga(hol, d1z.statement, (st) => { st.kind = 'aere-delegation-v0'; })], phone),
linkIds: resemneaza(prezD([veriga(hol, d1z.statement, (st) => { st.to.id = fals; })], phone), phone, (q) => { q.binding.presenter.id = fals; }),
linkFromStranger: prezD([ID.delegate({ from: strain, to: phone.public, scope: scop, notBefore: at(0), notAfter: at(zi), now: la(0) })], phone),
linkNoParent: prezD([d1, ID.delegate({ from: phone, to: sess.public, scope: ingust, notBefore: at(30), notAfter: at(600), maxDepth: 0, now: la(30) })], sess),
linkSignature: semnaturaVerigii,
linkScopeUnknownField: prezD([veriga(hol, d1z.statement, (st) => { st.scope.extra = ['x']; })], phone),
linkScopeUnsorted: prezD([veriga(hol, d1z.statement, (st) => { st.scope.claims = ['member_since', 'age_over_18']; })], phone),
linkExpired: prezD([una({ notBefore: at(-7200), notAfter: at(-3600) })], phone),
linkDepthZero: prezD([d1z, veriga(phone, d2.statement, (st) => { st.parent = ID.delegationHash(d1z); })], sess),
linkDepthNegative: prezD([d1z, veriga(phone, d2.statement, (st) => { st.parent = ID.delegationHash(d1z); st.maxDepth = -1; })], sess),
linkWidens: prezD([d1, veriga(phone, d2.statement, (st) => { st.scope.claims = '*'; })], sess),
linkOtherCredential: prezD([una({ scope: scopul([altId], scop.claims, scop.audiences) })], phone),
linkOtherClaims: prezD([una({ scope: ingust })], phone, { reveal: ['age_over_18', 'name'] }),
linkOtherAudience: prezD([una({ scope: { ...scop, audiences: ['https://other.example'] } })], phone) } };
},
};
// ---------- fixed inputs of the AIP-23 kinds (the inputs of the published AIP-23 kind vectors) ----------
function intrariKinds() {
const AT = '2026-09-26T00:00:00Z'; const H = (s) => sha256(Buffer.from(s, 'utf8'));
return { data: { name: 'report.csv', content: 'a,b,c', createdAt: AT }, execution: { program: 'aere-node', input: 'in', output: 'out', exitCode: 0, createdAt: AT },
identity: { subjectId: 'agent-1', publicKey: 'PK', method: 'ml-dsa-65', createdAt: AT }, compliance: { subject: 'org-x', policy: 'pq-ready', result: 'pass', evidence: 'EV', createdAt: AT },
runtime: { host: 'h1', artifactContent: 'BIN', attested: H('BIN'), matches: true, createdAt: AT }, location: { subject: 'srv-eu', region: 'eu-central', evidence: 'EV', createdAt: AT },
device: { deviceId: 'dev-9', attestation: 'ATT', publicKey: 'PK', posture: 'secure-boot', createdAt: AT }, payment: { from: '0xa', to: '0xb', amount: '100', asset: 'AERE', tx: 'TX', createdAt: AT },
ownership: { owner: '0xowner', assetId: 'nft-7', asset: 'ASSET', createdAt: AT }, time: { subject: 'SUBJ', source: 'aere-anchor', at: AT, createdAt: AT },
block: { blockHash: '0x' + 'ab'.repeat(32), stateRoot: '0x' + 'cd'.repeat(32), anchorHeight: 20255488, certificateDigest: '0x' + 'ef'.repeat(32), createdAt: AT },
authorization: { grantor: 'org-x', grantee: 'agent-7', scope: 'payments:send<=100', policy: 'POLICY', expiresAt: '2026-12-31T00:00:00Z', createdAt: AT },
settlement: { chainId: 2800, txHash: '0x' + '12'.repeat(32), blockHash: '0x' + '34'.repeat(32), from: '0xa', to: '0xb', amount: '100', asset: 'AERE', instruction: 'INSTR', createdAt: AT },
provenance: { subject: 'ARTIFACT', parents: ['SRC-1', 'SRC-2'], process: 'BUILD', actor: 'build-bot', createdAt: AT } };
}
/** Every AIP-23 kind, from its producer, on the fixed inputs. */
export function plicuriKinds() {
const AT = '2026-09-26T00:00:00Z'; const INT = intrariKinds(); const out = [];
for (const k of KINDS) { if (!INT[k]) throw new Error('proof kind ' + k + ' has no fixed input here: a new kind needs its vectors'); out.push([k, buildProof(k, INT[k])]); }
out.push(['ai', buildProofOfAi({ model: { name: 'example-model', version: '1.0' }, prompt: 'summarize', output: 'summary', tools: ['search'], agentId: 'agent-7', createdAt: AT })]);
const { policy, policyHash } = definePolicy({ agentId: 'agent-7', spend: { amount: '100', windowSeconds: 3600, asset: 'AERE' }, tools: ['search'], recipients: null });
const action = { kind: 'payment', to: '0xb', amount: '50', at: 1 };
out.push(['agent-decision', decisionEnvelope({ policyHash, action, decision: checkAction(policy, action, []), createdAt: AT })]);
return out;
}
// ---------- the vectors ----------
function construieste() {
if (!fs.existsSync(PROASPETE)) throw new Error('surse-proaspete.json is missing: run with --proaspat once (it reads testnet 28001)');
const P = JSON.parse(fs.readFileSync(PROASPETE, 'utf8'));
const E = ['envelope.form', 'envelope.integrity'];
// (A) AIP-23 envelopes: every kind VALID; its statementHash cut short (form); one statement field changed (integrity)
for (const [k, env] of plicuriKinds()) {
valid(`envelope/${k}.valid`, 'envelope', `the ${k} envelope from its producer`, 'producer on fixed inputs', { envelope: env }, { exercises: E });
invalid(`envelope/${k}.form`, `${k}: the statementHash is 63 hex digits`, `envelope/${k}.valid`, { op: 'set', path: ['envelope', 'statementHash'], value: env.statementHash.slice(0, -1) }, ['envelope.form']);
const camp = Object.keys(env.statement).find((c) => c !== 'kind' && typeof env.statement[c] === 'string'); if (!camp) throw new Error('kind ' + k + ' has no string field to change');
invalid(`envelope/${k}.integrity`, `${k}: statement.${camp} changed after hashing`, `envelope/${k}.valid`, { op: 'set', path: ['envelope', 'statement', camp], value: env.statement[camp] + '0' }, ['envelope.integrity']);
}
// files that are not envelopes at all: one base (the data envelope), the whole file replaced
{ const b = 'envelope/data.valid'; const env = V.find((x) => x.id === b).input.envelope;
const nuPlic = (nume, titlu, v) => invalid('envelope/data.' + nume, titlu, b, { op: 'set', path: ['envelope'], value: v }, ['envelope.form']);
nuPlic('form-null', 'the file holds the JSON value null', null); nuPlic('form-number', 'the file holds a number', 7); nuPlic('form-string', 'the file holds a string', 'x');
nuPlic('form-true', 'the file holds true', true); nuPlic('form-list', 'the file holds a list with the envelope inside', [env]);
const lista = '[]';
invalid('envelope/data.form-statement-list', 'the statement is a list, with the hash of that list', b, null, ['envelope.form'], { producer: { note: 'a producer that made the statement a list and hashed it', input: { envelope: { ...clona(env), statement: [], statementHash: sha256(Buffer.from(lista, 'utf8')) } }, changed: [['envelope', 'statement'], ['envelope', 'statementHash']] } });
invalid('envelope/data.form-not-json', 'the file is not JSON (the envelope cut short)', b, null, ['envelope.form'], { producer: { note: 'the file holds text that is not JSON: the input carries it as `raw`, the text of the file, in place of `envelope`', input: { raw: JSON.stringify(env).slice(0, 60) }, changed: [['envelope'], ['raw']] } }); }
// a signed envelope: the tree head of an audit log, ML-DSA-65
const b64 = P.signedHead.signature.signature;
valid('envelope/signed-head.valid', 'envelope', 'a tree head signed with ML-DSA-65', 'producer (verify-layer tree head), key made and discarded at generation', { envelope: P.signedHead }, { exercises: [...E, 'envelope.signature'], levels: { authenticity: 'PASSED' } });
invalid('envelope/signed-head.signature', 'the signature has one character changed', 'envelope/signed-head.valid', { op: 'set', path: ['envelope', 'signature', 'signature'], value: (b64[0] === 'A' ? 'B' : 'A') + b64.slice(1) }, ['envelope.signature']);
invalid('envelope/signed-head.signature-classical-key', 'the signature declares ml-dsa-65 and was made with an Ed25519 key: a classical signature is not a post-quantum one because it says so', 'envelope/signed-head.valid', null, ['envelope.signature'],
{ producer: { note: 'the signer used a classical key (Ed25519, made and discarded at generation) and declared the scheme ml-dsa-65', input: { envelope: P.classicalHead }, changed: [['envelope', 'signature', 'publicKey'], ['envelope', 'signature', 'signature']] } });
invalid('envelope/signed-head.signature-not-object', 'the signature field is a string', 'envelope/signed-head.valid', { op: 'set', path: ['envelope', 'signature'], value: 'signed' }, ['envelope.signature']);
invalid('envelope/signed-head.signature-no-key', 'the signature carries no public key', 'envelope/signed-head.valid', { op: 'remove', path: ['envelope', 'signature', 'publicKey'] }, ['envelope.signature']);
// notarization: a recorded envelope on 28001 (online), the same judged offline (the claim is not checked), a fresh one with a false claim
const D = citeste(DOV.date); const F = [...E, 'envelope.finality']; const R = ['rpc-28001'];
valid('envelope/notarized-28001.valid', 'envelope', 'a dataset commitment notarized on testnet 28001, read back under a verified post-quantum anchor', 'recorded (verifiable-data, 2026-10-02)', { envelope: D.envelope, chain: 28001 }, { exercises: F, requires: R, levels: { anchoring: 'PASSED', finality: 'PASSED' } });
valid('envelope/notarized-claim.partial', 'envelope', 'the same envelope judged offline: the notarization it claims is not checked, so it is not VALID', 'recorded (verifiable-data, 2026-10-02)', { envelope: D.envelope, chain: 28001 }, { exercises: E, verdict: 'PARTIAL' });
valid('envelope/fresh-28001.valid', 'envelope', 'an envelope nobody notarized, claiming nothing', 'producer, random content', { envelope: P.fresh, chain: 28001 }, { exercises: F, requires: R });
invalid('envelope/fresh-28001.finality', 'the same envelope claims a notarization the chain does not hold', 'envelope/fresh-28001.valid', { op: 'add', path: ['envelope', 'notarization'], value: { chainId: 28001 } }, ['envelope.finality']);
// (B) a payment under a declared policy: the recorded payment P1, then one input changed per rule
const C = citeste(DOV.chitanta); const RK = Object.keys(HARTA).filter((r) => r.startsWith('risk.'));
valid('payment-risk/company-p1.valid', 'payment-risk', 'the recorded payment to a company, allowed by its policy', 'recorded (payments, 2026-10-02)', { policy: C.policy, inputs: C.inputs }, { exercises: RK });
const ref = C.policy.refusedCounterparties[0].address; const acum = C.inputs.now;
const risc = (nume, titlu, op, r) => invalid('payment-risk/company-p1.' + nume, titlu, 'payment-risk/company-p1.valid', op, [r]);
risc('form', 'the payer is not an address', { op: 'set', path: ['inputs', 'payer'], value: '0x1234' }, 'risk.form');
risc('form-amount', 'the amount is zero', { op: 'set', path: ['inputs', 'amount'], value: '0' }, 'risk.form');
risc('form-time', 'no time given', { op: 'remove', path: ['inputs', 'now'] }, 'risk.form');
risc('form-history', 'a history entry the engine cannot count (it is refused, not left out of the window)', { op: 'set', path: ['inputs', 'history'], value: [{ at: 'yesterday', amountUsd: '0.100000' }] }, 'risk.form');
risc('asset', 'an asset the policy does not allow', { op: 'set', path: ['inputs', 'asset'], value: 'other-token' }, 'risk.asset');
risc('counterparty', 'the payee is a refused counterparty of the policy', { op: 'set', path: ['inputs', 'payee'], value: ref }, 'risk.counterparty');
risc('rate', 'no USD rate declared, and the policy requires one', { op: 'remove', path: ['inputs', 'rate'] }, 'risk.rate');
risc('rate-number', 'the USD rate given as a JSON number instead of a decimal string (refused, not rounded)', { op: 'set', path: ['inputs', 'rate', 'usdPerUnit'], value: 0.5 }, 'risk.rate');
risc('limit', 'an amount above the per-payment limit', { op: 'set', path: ['inputs', 'amount'], value: '2400000000000000000' }, 'risk.limit');
risc('window', 'three payments already in the window (the fourth is one too many)', { op: 'set', path: ['inputs', 'history'], value: [1, 2, 3].map((s) => ({ at: acum - 10 * s, amountUsd: '0.100000' })) }, 'risk.window');
// (C) the receipt of that payment: as the issuer built it; with its notarization claim (offline: PARTIAL; online: VALID)
const CK = [...Object.keys(HARTA).filter((r) => r.startsWith('receipt.')), ...E]; const claim = C.envelope.notarization; const env0 = clona(C.envelope); delete env0.notarization;
const rb = 'payment-receipt/company-p1.valid'; const tx = P.receiptTx;
valid(rb, 'payment-receipt', 'the recorded receipt as its issuer built it, with the policy, the inputs judged and the transaction read from the chain', 'recorded (payments, 2026-10-02); transaction read from 28001 at ' + tx.readAt, { receipt: { instruction: C.instruction, envelope: env0 }, policy: C.policy, inputs: C.inputs, tx: tx.tx, txReceipt: tx.txReceipt, chain: 28001 }, { exercises: CK });
const chit = (nume, titlu, op, r, o) => invalid('payment-receipt/company-p1.' + nume, titlu, rb, op, r, o);
chit('binding', 'the purpose on the instruction changed after the envelope committed to it', { op: 'set', path: ['receipt', 'instruction', 'purpose'], value: C.instruction.purpose + ' (edited)' }, ['receipt.binding']);
chit('policy', 'a looser policy shown in place of the one under the hash (so the verdict does not reproduce either)', { op: 'set', path: ['policy', 'perPaymentMaxUsd'], value: '1000.000000' }, ['receipt.policy', 'receipt.risk']);
chit('risk', 'other inputs shown than the ones the issuer judged', { op: 'set', path: ['inputs', 'now'], value: C.inputs.now + 1 }, ['receipt.risk']);
chit('chain', 'the transaction on chain pays someone else', { op: 'set', path: ['tx', 'to'], value: C.policy.refusedCounterparties[0].address }, ['receipt.chain']);
{ // the amount in USD sits under the instruction hash: the issuer writes another amount and commits to it
const r = { instruction: clona(C.instruction), envelope: clona(env0) }; r.instruction.amountUsd = '0.300000';
r.envelope.statement.instructionHash = sha256(Buffer.from(RISC.canonical(r.instruction), 'utf8')); r.envelope.statementHash = sha256(Buffer.from(JSON.stringify(r.envelope.statement), 'utf8'));
const b = V.find((x) => x.id === rb);
chit('amount', 'the issuer wrote a USD amount that is not the amount at the declared rate, and committed to it', null, ['receipt.amount'], { producer: { note: 'instruction.amountUsd changed by the issuer; instructionHash and statementHash recomputed with the published formulas', input: { ...clona(b.input), receipt: r },
changed: [['receipt', 'instruction', 'amountUsd'], ['receipt', 'envelope', 'statement', 'instructionHash'], ['receipt', 'envelope', 'statementHash']] } });
}
{ // the risk verdict sits under the instruction hash: the issuer attaches a verdict made for ANOTHER payment and commits to it
const b = V.find((x) => x.id === rb); const reangajeaza = (r) => { r.envelope.statement.instructionHash = sha256(Buffer.from(RISC.canonical(r.instruction), 'utf8')); r.envelope.statementHash = sha256(Buffer.from(JSON.stringify(r.envelope.statement), 'utf8')); return r; };
const cuVerdict = (inputs) => { const v = RISC.judeca(C.policy, inputs); if (v.decision !== 'ALLOW') throw new Error('the reused verdict must be an ALLOW'); const r = { instruction: clona(C.instruction), envelope: clona(env0) };
r.instruction.risk = { ...r.instruction.risk, policyHash: v.policyHash, inputsHash: v.inputsHash, verdictHash: v.verdictHash, decision: v.decision, unmeasured: v.unmeasured }; return { ...clona(b.input), receipt: reangajeaza(r), inputs }; };
const H = [['receipt', 'instruction', 'risk', 'inputsHash'], ['receipt', 'instruction', 'risk', 'verdictHash'], ['receipt', 'envelope', 'statement', 'instructionHash'], ['receipt', 'envelope', 'statementHash']];
chit('risk-other-payment', 'the issuer attached an ALLOW verdict that was made for a payment to someone else', null, ['receipt.risk'], { producer: { note: 'the risk verdict was computed for another payee; its hashes are on the instruction; instructionHash and statementHash recomputed', input: cuVerdict({ ...clona(C.inputs), payee: '0x' + '11'.repeat(20) }), changed: [['inputs', 'payee'], ...H] } });
chit('risk-other-rate', 'the issuer attached an ALLOW verdict that was made at another USD rate than the one on the receipt', null, ['receipt.risk'], { producer: { note: 'the risk verdict was computed at another rate; its hashes are on the instruction; instructionHash and statementHash recomputed', input: cuVerdict({ ...clona(C.inputs), rate: { ...C.inputs.rate, usdPerUnit: '0.25' } }), changed: [['inputs', 'rate', 'usdPerUnit'], ...H] } }); }
const cuClaim = { op: 'add', path: ['receipt', 'envelope', 'notarization'], value: claim };
{ const b = V.find((x) => x.id === rb); const inp = aplica(b.input, cuClaim);
valid('payment-receipt/company-p1-claim.partial', 'payment-receipt', 'the notarized receipt judged offline: its notarization claim is not checked', 'recorded (payments, 2026-10-02)', inp, { exercises: CK, verdict: 'PARTIAL', base: rb, mutation: cuClaim });
valid('payment-receipt/company-p1-28001.valid', 'payment-receipt', 'the notarized receipt judged with the chain: integrity, anchoring and finality in one verdict', 'recorded (payments, 2026-10-02)', inp, { exercises: [...CK, 'envelope.finality'], requires: R, levels: { anchoring: 'PASSED', finality: 'PASSED' }, base: rb, mutation: cuClaim }); }
// (D) market timelines recorded on 28001. The public task (`spec`) stays in the input only where the replay rule is exercised:
// each replay recomputes the task and costs seconds.
const M = citeste(DOV.piata).scenarii; const MK = Object.keys(HARTA).filter((r) => r.startsWith('market.'));
const tl = (s, cuSpec) => { const d = clona(M[s].date); if (!cuSpec) delete d.spec; if (d.envelope === null) delete d.envelope; return d; };
const mv = (id, s, titlu, o = {}) => valid('market-timeline/' + id, 'market-timeline', titlu, 'recorded (market-settlement, 2026-10-02), scenario ' + s, tl(s, o.spec), { exercises: o.exercises || MK, verdict: o.verdict, requires: o.requires, levels: o.levels });
mv('s2-slashed.valid', 'S2', 'a dispute the challenger won: the provider slashed');
mv('s3-paid-after-dispute.valid', 'S3', 'a dispute the provider won');
mv('s3-paid-after-dispute-replayed.valid', 'S3', 'the same timeline with the public task: the judge recomputes it and agrees with the arbiter', { spec: true });
mv('s4-refunded-expired.valid', 'S4', 'claimed and never delivered: the escrow reclaimed after the deadline');
mv('s5-refunded-cancelled.valid', 'S5', 'posted and cancelled: the escrow returned');
mv('s1-paid-claim.partial', 'S1', 'accepted and paid; its execution envelope claims a notarization that an offline run does not check', { exercises: [...MK, ...E], verdict: 'PARTIAL' });
mv('s1-paid-28001.valid', 'S1', 'the same timeline judged with the chain: the execution envelope is under a verified post-quantum anchor', { exercises: [...MK, ...F], requires: R, levels: { anchoring: 'PASSED', finality: 'PASSED' } });
const ev = (d, n) => d.events.findIndex((e) => e.name === n); const S = (s) => V.find((x) => x.id === 'market-timeline/' + s).input;
const piata = (nume, titlu, baza, op, r) => invalid('market-timeline/' + nume, titlu, 'market-timeline/' + baza, op, r);
{ const d = S('s2-slashed.valid'); const j = d.job;
piata('s2.posting', 'the JobPosted event names another requester than the job', 's2-slashed.valid', { op: 'set', path: ['events', ev(d, 'JobPosted'), 'args', 'requester'], value: j.provider }, ['market.posting']);
piata('s2.window', 'the dispute was raised after the challenge window closed', 's2-slashed.valid', { op: 'set', path: ['events', ev(d, 'JobDisputed'), 'timestamp'], value: j.submittedAt + j.challengeWindow + 5 }, ['market.window']);
piata('s2.deadline-submitted', 'the result was submitted after the deadline', 's2-slashed.valid', { op: 'set', path: ['events', ev(d, 'ResultSubmitted'), 'timestamp'], value: j.deadline + 1 }, ['market.deadline']);
piata('s2.arbiter', 'the dispute was resolved by an address that is not the arbiter', 's2-slashed.valid', { op: 'set', path: ['events', ev(d, 'DisputeResolved'), 'from'], value: j.requester }, ['market.arbiter']);
piata('s2.payout', 'the slashed bond is paid to someone who is not the challenger', 's2-slashed.valid', { op: 'set', path: ['events', ev(d, 'JobSlashed'), 'args', 'challenger'], value: j.provider }, ['market.payout']);
piata('s2.result', 'the result bytes shown do not hash to the commitment on chain', 's2-slashed.valid', { op: 'set', path: ['result'], value: d.result.slice(0, -2) + (d.result.endsWith('00') ? '01' : '00') }, ['market.result']); }
{ const d = S('s3-paid-after-dispute.valid');
piata('s3.payout', 'the payout names someone who is not the provider', 's3-paid-after-dispute.valid', { op: 'set', path: ['events', ev(d, 'JobPaid'), 'args', 'provider'], value: d.job.requester }, ['market.payout']);
piata('s3.arbiter-no-dispute', 'the dispute withheld from the timeline: a resolution with no dispute, and an event the job state implies is missing', 's3-paid-after-dispute.valid', { op: 'remove', path: ['events', ev(d, 'JobDisputed')] }, ['market.arbiter', 'market.complete']);
piata('s3.replay', 'another task shown than the one the job committed to: the recomputation contradicts the arbiter', 's3-paid-after-dispute-replayed.valid', { op: 'set', path: ['spec', 'seed'], value: '0x' + 'ab'.repeat(32) }, ['market.replay']); }
{ const d = S('s4-refunded-expired.valid');
piata('s4.deadline', 'the escrow was reclaimed as expired before the deadline', 's4-refunded-expired.valid', { op: 'set', path: ['events', ev(d, 'JobRefunded'), 'timestamp'], value: d.job.deadline - 1 }, ['market.deadline']);
piata('s4.complete-claim', 'the claim withheld from the timeline (the job state names a provider)', 's4-refunded-expired.valid', { op: 'remove', path: ['events', ev(d, 'JobClaimed')] }, ['market.complete']);
piata('s4.payout', 'the refund names someone who is not the requester', 's4-refunded-expired.valid', { op: 'set', path: ['events', ev(d, 'JobRefunded'), 'args', 'requester'], value: d.job.provider }, ['market.payout']); }
{ const d = S('s5-refunded-cancelled.valid');
piata('s5.form', 'an event whose time is not a whole number of seconds', 's5-refunded-cancelled.valid', { op: 'set', path: ['events', ev(d, 'JobPosted'), 'timestamp'], value: d.events[ev(d, 'JobPosted')].timestamp + 0.5 }, ['market.form']); }
{ const d = S('s1-paid-claim.partial'); const j = d.job;
piata('s1.window', 'a third party finalized inside the challenge window', 's1-paid-claim.partial', { op: 'set', path: ['events', ev(d, 'JobPaid'), 'timestamp'], value: j.submittedAt + 1 }, ['market.window']);
piata('s1.complete-submission', 'the submission withheld from the timeline (the job state has a submission time)', 's1-paid-claim.partial', { op: 'remove', path: ['events', ev(d, 'ResultSubmitted')] }, ['market.complete']);
piata('s1.deadline', 'the job was claimed after its deadline', 's1-paid-claim.partial', { op: 'set', path: ['events', ev(d, 'JobClaimed'), 'timestamp'], value: j.deadline + 1 }, ['market.deadline']);
piata('s1.proof-late', 'the execution envelope was notarized only after the challenge window closed', 's1-paid-claim.partial', { op: 'set', path: ['envelope', 'notarization', 'firstSeen'], value: j.submittedAt + j.challengeWindow + 1 }, ['market.proof']);
invalid('market-timeline/s1-28001.proof-claim-early', 'the envelope claims it was notarized earlier than the chain, read under the anchor, says', 'market-timeline/s1-paid-28001.valid', { op: 'set', path: ['envelope', 'notarization', 'firstSeen'], value: d.envelope.notarization.firstSeen - 600 }, ['market.proof']);
piata('s1.proof-other-result', 'the execution envelope names another result (and so no longer hashes to its statementHash)', 's1-paid-claim.partial', { op: 'set', path: ['envelope', 'statement', 'outputHash'], value: '0x' + 'cc'.repeat(32) }, ['envelope.integrity', 'market.proof']); }
// (F) the trust chain of an AI result (ai-trust): the bundle recorded on 28001 with its witness, and three made by one fresh agent
{ const AK = Object.keys(HARTA).filter((r) => r.startsWith('aitrust.')); const B = citeste(DOV.lantAI).bundle; const A = 'ai-trust-bundle'; const src = 'recorded (ai-trust, 2026-10-02)';
const fara = AK.filter((r) => !['aitrust.witness-head', 'aitrust.provenance-finality'].includes(r)); const L = { authenticity: 'PASSED' };
const bo = 'ai-trust/recorded.partial', bl = 'ai-trust/recorded-28001.valid';
valid(bo, A, 'the recorded trust chain judged offline: every link holds, the notarized heads it brings are not read', src, { bundle: B, chain: 28001 }, { exercises: fara, verdict: 'PARTIAL', levels: L });
valid(bl, A, 'the same trust chain with the chain: the ledger head is under a verified post-quantum anchor', src, { bundle: B, chain: 28001 }, { exercises: AK, requires: R, levels: { ...L, anchoring: 'PASSED', finality: 'PASSED' } });
const lv = (nume, titlu, op, r, o) => invalid('ai-trust/recorded.' + nume, titlu, bo, op, r, o); const altHex = (h) => h.slice(0, -1) + (h.endsWith('0') ? '1' : '0');
const rehash = (e) => { e.statementHash = sha256(Buffer.from(JSON.stringify(e.statement), 'utf8')); return e; }; const cu = (f) => { const b = clona(B); f(b); return { bundle: b, chain: 28001 }; };
lv('form', 'the bundle declares another format', { op: 'set', path: ['bundle', 'format'], value: 'another-format' }, ['aitrust.form'], { levels: { authenticity: 'NOT_MEASURED' } });
lv('identity-mismatch', 'the bundle names another agent than the key derives', { op: 'set', path: ['bundle', 'identity', 'agentId'], value: 'aere-agent:' + '11'.repeat(20) }, ['aitrust.identity-mismatch']);
lv('identity-key', 'the public key of the identity is not a key', { op: 'set', path: ['bundle', 'identity', 'publicKeyPem'], value: 'not a key' }, ['aitrust.identity-key']);
lv('version-attestation', 'the model attestation changed after it was hashed', { op: 'set', path: ['bundle', 'version', 'attestation', 'statement', 'artifacts', 0, 'sha256'], value: '0x' + 'ef'.repeat(32) }, ['aitrust.version-attestation']);
lv('version-artifact-mismatch', 'the attestation covers another artifact than the weights the output names', null, ['aitrust.version-artifact-mismatch'], { producer: { note: 'the attester attested another artifact digest (statement rehashed)', input: cu((b) => { b.version.attestation.statement.artifacts[0].sha256 = '0x' + 'ab'.repeat(32); rehash(b.version.attestation); }), changed: [['bundle', 'version', 'attestation', 'statement', 'artifacts', 0, 'sha256'], ['bundle', 'version', 'attestation', 'statementHash']] } });
lv('version-label-mismatch', 'the attestation names another model version than the output', null, ['aitrust.version-label-mismatch'], { producer: { note: 'the attester attested another version label (statement rehashed)', input: cu((b) => { b.version.attestation.statement.subject.version = String(b.version.attestation.statement.subject.version) + '-other'; rehash(b.version.attestation); }), changed: [['bundle', 'version', 'attestation', 'statement', 'subject', 'version'], ['bundle', 'version', 'attestation', 'statementHash']] } });
lv('runtime-record', 'the runtime record is an envelope of another kind', { op: 'set', path: ['bundle', 'runtime', 'record', 'kind'], value: 'aere-proof-of-data-attestation' }, ['aitrust.runtime-record']);
lv('runtime-artifact-mismatch', 'the host declared another artifact running', null, ['aitrust.runtime-artifact-mismatch'], { producer: { note: 'the host recorded another artifact digest (statement rehashed)', input: cu((b) => { b.runtime.record.statement.artifactSha256 = '0x' + 'cd'.repeat(32); rehash(b.runtime.record); }), changed: [['bundle', 'runtime', 'record', 'statement', 'artifactSha256'], ['bundle', 'runtime', 'record', 'statementHash']] } });
lv('runtime-after-output', 'the runtime record is dated an hour after the output', null, ['aitrust.runtime-after-output'], { producer: { note: 'the host dated its record after the output (statement rehashed)', input: cu((b) => { b.runtime.record.statement.createdAt = new Date(Date.parse(b.provenance.proofOfAi.statement.createdAt) + 3600000).toISOString(); rehash(b.runtime.record); }), changed: [['bundle', 'runtime', 'record', 'statement', 'createdAt'], ['bundle', 'runtime', 'record', 'statementHash']] } });
lv('audit-log-broken', 'one entry hash of the audit log changed', { op: 'set', path: ['bundle', 'runtime', 'auditLog', 0, 'hash'], value: altHex(B.runtime.auditLog[0].hash) }, ['aitrust.audit-log-broken']);
lv('runtime-not-in-audit-log', 'an audit log that does not hold the runtime record', { op: 'set', path: ['bundle', 'runtime', 'auditLog'], value: [] }, ['aitrust.runtime-not-in-audit-log']);
lv('audit-head', 'the attested head of the audit log changed after it was hashed', { op: 'set', path: ['bundle', 'runtime', 'head', 'statementHash'], value: altHex(B.runtime.head.statementHash) }, ['aitrust.audit-head']);
lv('policy-hash', 'the bundle pins another policy hash than the policy it shows', { op: 'set', path: ['bundle', 'permissions', 'policyHash'], value: altHex(B.permissions.policyHash) }, ['aitrust.policy-hash']);
lv('policy', 'the policy shown is not a policy', { op: 'set', path: ['bundle', 'permissions', 'policy'], value: 'no policy' }, ['aitrust.policy']);
lv('ledger-invalid', 'a ledger entry changed after it was signed', { op: 'set', path: ['bundle', 'permissions', 'ledger', 'entries', 0, 'body', 'action', 'args'], value: { promptHash: '0x' + '00'.repeat(32) } }, ['aitrust.ledger-invalid']);
lv('output-not-in-ledger', 'another output than the one the ledger entry links', null, ['aitrust.output-not-in-ledger'], { producer: { note: 'the producer of the output wrote another output digest (statement rehashed); the ledger still links the first', input: cu((b) => { b.provenance.proofOfAi.statement.outputHash = sha256(Buffer.from('another output', 'utf8')); rehash(b.provenance.proofOfAi); }), changed: [['bundle', 'provenance', 'proofOfAi', 'statement', 'outputHash'], ['bundle', 'provenance', 'proofOfAi', 'statementHash']] } });
lv('provenance-envelope', 'the Proof of AI envelope is of another kind (and so is no longer what the ledger links)', { op: 'set', path: ['bundle', 'provenance', 'proofOfAi', 'kind'], value: 'aere-proof-of-data-attestation' }, ['aitrust.output-not-in-ledger', 'aitrust.provenance-envelope']);
invalid('ai-trust/recorded-28001.witness-head', 'a notarized head that is not a head of this ledger', bl, { op: 'set', path: ['bundle', 'witness', 'heads', 0, 'statementHash'], value: altHex(B.witness.heads[0].statementHash) }, ['aitrust.witness-head'], { levels: { anchoring: 'FAILED', finality: 'NOT_MEASURED' } });
invalid('ai-trust/recorded-28001.provenance-finality', 'the Proof of AI envelope claims a notarization the chain does not hold (and so is no longer what the ledger links)', bl, { op: 'add', path: ['bundle', 'provenance', 'proofOfAi', 'notarization'], value: { chainId: 28001 } }, ['aitrust.output-not-in-ledger', 'aitrust.provenance-finality'], { levels: { anchoring: 'FAILED', finality: 'PASSED' } });
// one fresh agent, three chains: allowed (no witness at all), refused by the policy, dated apart
const T = P.aiTrust; const fb = 'ai-trust/fresh-agent.partial'; const fsrc = 'producers (agents ledger, Proof of AI), one agent key made and discarded at generation';
valid(fb, A, 'a trust chain with no witness: the links hold, and nobody but the agent fixed a time', fsrc, { bundle: T.allowed }, { exercises: fara, verdict: 'PARTIAL', levels: L });
invalid('ai-trust/fresh-agent.action-refused', 'the same action under a policy that does not allow the tool: the ledger entry of the output is a refusal', fb, null, ['aitrust.action-refused'], { producer: { note: 'the owner\'s policy lists another tool; the agent recorded the action and the ledger holds the refusal', input: { bundle: T.refused }, changed: [['bundle', 'permissions']] } });
invalid('ai-trust/fresh-agent.ledger-time-mismatch', 'the output is dated two hours before its ledger entry', fb, null, ['aitrust.ledger-time-mismatch'], { producer: { note: 'the producer dated the output two hours before the agent recorded it', input: { bundle: T.lateEntry }, changed: [['bundle', 'permissions'], ['bundle', 'provenance']] } }); }
// (G) an audit log (verify-layer): the chain, an attested head, a signed head; inclusion and consistency against tree heads
{ const LK = Object.keys(HARTA).filter((r) => r.startsWith('auditlog.')), TK = Object.keys(HARTA).filter((r) => r.startsWith('audittree.')); const sig = ['auditlog.head-unsigned', 'auditlog.head-scheme', 'auditlog.head-key', 'auditlog.head-signature', 'auditlog.head-signer'];
const lant = LK.filter((r) => !r.includes('.head-')), cuCap = LK.filter((r) => !sig.includes(r)); const log = jurnalAudit(), patru = log.slice(0, 4), cap4 = capAudit(log, 4); const AH = P.auditHead;
const altHex = (h) => h.slice(0, -1) + (h.endsWith('0') ? '1' : '0'); const src = 'producers (verify-layer log and tree) on the fixed inputs';
const NA = { integrity: 'NOT_MEASURED', authenticity: 'FAILED' };
valid('audit-log/six-entries.valid', 'audit-log', 'a log of six entries, its hash chain intact', src, { log }, { exercises: lant });
const lg = (nume, titlu, op, r) => invalid('audit-log/six-entries.' + nume, titlu, 'audit-log/six-entries.valid', op, [r]);
lg('entry', 'an entry of the log is not a log entry', { op: 'set', path: ['log', 1], value: 'not an entry' }, 'auditlog.entry');
lg('seq', 'an entry carries another sequence number', { op: 'set', path: ['log', 1, 'seq'], value: 5 }, 'auditlog.seq');
lg('chain', 'an entry does not link the one before it', { op: 'set', path: ['log', 2, 'prev'], value: altHex(log[2].prev) }, 'auditlog.chain');
lg('hash', 'the hash of the last entry is not the hash of its content', { op: 'set', path: ['log', 5, 'hash'], value: altHex(log[5].hash) }, 'auditlog.hash');
const bh = 'audit-log/head-at-four.valid';
valid(bh, 'audit-log', 'four entries and the attested head that covers them', src, { log: patru, head: cap4 }, { exercises: cuCap });
const hd = (nume, titlu, op, r, o) => invalid('audit-log/head-at-four.' + nume, titlu, bh, op, [r], o);
hd('head-form', 'the head is an attestation of another kind', { op: 'set', path: ['head', 'kind'], value: 'aere-proof-of-data-attestation' }, 'auditlog.head-form');
hd('head-hash', 'the head changed after it was hashed', { op: 'set', path: ['head', 'statementHash'], value: altHex(cap4.statementHash) }, 'auditlog.head-hash');
hd('head-short', 'the last attested entry removed from the log', { op: 'remove', path: ['log', 3] }, 'auditlog.head-short');
{ const rescris = jurnalAudit((seq, proof) => { if (seq === 1) { proof.statement.createdAt = '2026-09-27T00:00:00Z'; proof.statementHash = sha256(Buffer.from(JSON.stringify(proof.statement), 'utf8')); } }).slice(0, 4);
hd('head-rewritten', 'the host rewrote an entry before the attested point and chained the log again', null, 'auditlog.head-rewritten', { producer: { note: 'entry 1 rewritten (another envelope), every later entry re-chained; the head is the one attested before', input: { log: rescris, head: cap4 }, changed: [['log', 1], ['log', 2], ['log', 3]] } }); }
const bs = 'audit-log/signed-head.valid'; const b64 = AH.signed.signature.signature;
valid(bs, 'audit-log', 'the same log against its head signed by the operator (ML-DSA-65), with the signer expected', src + '; operator key made and discarded at generation', { log: patru, head: AH.signed, signer: AH.signerPem }, { exercises: LK, levels: { authenticity: 'PASSED' } });
const sg = (nume, titlu, op, r, o = {}) => invalid('audit-log/signed-head.' + nume, titlu, bs, op, [r], { levels: NA, ...o });
sg('head-unsigned', 'the signature taken off a head whose signer is required', { op: 'remove', path: ['head', 'signature'] }, 'auditlog.head-unsigned');
sg('head-scheme', 'the head signature declares another scheme', { op: 'set', path: ['head', 'signature', 'scheme'], value: 'ed25519' }, 'auditlog.head-scheme');
sg('head-scheme-classical-key', 'the head is signed with an Ed25519 key that declares ml-dsa-65', null, 'auditlog.head-scheme', { producer: { note: 'the signer used a classical key (made and discarded at generation) and declared the scheme ml-dsa-65', input: { log: patru, head: AH.classical, signer: AH.signerPem }, changed: [['head', 'signature', 'publicKey'], ['head', 'signature', 'signature']] } });
sg('head-key', 'the public key of the head signature is not a key', { op: 'set', path: ['head', 'signature', 'publicKey'], value: 'AAAA' }, 'auditlog.head-key');
sg('head-signature', 'the head signature has one character changed', { op: 'set', path: ['head', 'signature', 'signature'], value: (b64[0] === 'A' ? 'B' : 'A') + b64.slice(1) }, 'auditlog.head-signature');
sg('head-signer', 'the head is signed, by another key than the signer expected', { op: 'set', path: ['signer'], value: AH.otherSignerPem }, 'auditlog.head-signer');
// the same signed head with NO signer expected (2026-10-05): the scheme rule is then all that stands between a classical key and acceptance
const bn = 'audit-log/signed-head-any-signer.valid';
valid(bn, 'audit-log', 'the same log against its signed head, with no signer expected: the head must still be signed with a key of the scheme it declares', src + '; operator key made and discarded at generation', { log: patru, head: AH.signed }, { exercises: LK, levels: { authenticity: 'PASSED' } });
invalid('audit-log/signed-head-any-signer.head-scheme-classical-key', 'the head is signed with an Ed25519 key that declares ml-dsa-65, and no signer is expected: without the scheme rule this head is accepted', bn, null, ['auditlog.head-scheme'],
{ levels: NA, producer: { note: 'the signer used a classical key (made and discarded at generation) and declared the scheme ml-dsa-65', input: { log: patru, head: AH.classical }, changed: [['head', 'signature', 'publicKey'], ['head', 'signature', 'signature']] } });
// the tree: inclusion of entry 2 under the head of six, consistency from the head of four to the head of six
const t6 = capDeArbore(log, { host: 'conformance', createdAt: '2026-10-03T00:00:00Z' }), t4 = capDeArbore(patru, { host: 'conformance', createdAt: '2026-10-03T00:00:00Z' }); const inc = dovadaIncludere(log, 2);
const bi = 'audit-inclusion/entry-2.valid'; const INC = TK.filter((r) => !r.includes('consistency'));
valid(bi, 'audit-inclusion', 'entry 2 proven in the tree of six entries, against its head', src, { proof: inc, head: t6 }, { exercises: INC });
const ic = (nume, titlu, op, r, o) => invalid('audit-inclusion/entry-2.' + nume, titlu, bi, op, [r], o);
ic('proof-form', 'the proof declares another kind', { op: 'set', path: ['proof', 'kind'], value: 'another-proof' }, 'audittree.proof-form');
ic('inclusion-index', 'the proof is for another index than the entry shown', { op: 'set', path: ['proof', 'index'], value: 3 }, 'audittree.inclusion-index');
ic('inclusion-entry', 'the entry shown changed after it was hashed', { op: 'set', path: ['proof', 'entry', 'prev'], value: altHex(inc.entry.prev) }, 'audittree.inclusion-entry');
ic('inclusion-leaf', 'the leaf is not the leaf of the entry shown', { op: 'set', path: ['proof', 'leafHash'], value: altHex(inc.leafHash) }, 'audittree.inclusion-leaf');
ic('inclusion-path', 'one hash of the path changed', { op: 'set', path: ['proof', 'path', 0], value: altHex(inc.path[0]) }, 'audittree.inclusion-path');
ic('inclusion-head', 'the head given is the head of another tree', { op: 'set', path: ['head'], value: t4 }, 'audittree.inclusion-head');
ic('head-form', 'the tree head is an attestation of another kind', { op: 'set', path: ['head', 'kind'], value: 'aere-audit-head-attestation' }, 'audittree.head-form');
ic('head-hash', 'the tree head changed after it was hashed', { op: 'set', path: ['head', 'statementHash'], value: altHex(t6.statementHash) }, 'audittree.head-hash');
{ const stricat = jurnalAudit((seq, proof) => { if (seq === 2) proof.statementHash = altHex(proof.statementHash); });
ic('inclusion-envelope', 'the host logged an envelope that does not hash to its statementHash: the entry is in the tree, and it is not an envelope', null, 'audittree.inclusion-envelope', { producer: { note: 'the host wrote a broken envelope into entry 2 and chained the log over it', input: { proof: dovadaIncludere(stricat, 2), head: capDeArbore(stricat, { host: 'conformance', createdAt: '2026-10-03T00:00:00Z' }) }, changed: [['proof'], ['head']] } }); }
const cons = dovadaConsistenta(log, 4); const bc = 'audit-consistency/four-to-six.valid';
valid(bc, 'audit-consistency', 'the tree of six entries extends the tree of four', src, { proof: cons, older: t4, newer: t6 }, { exercises: TK.filter((r) => !r.includes('inclusion')) });
const co = (nume, titlu, op, r) => invalid('audit-consistency/four-to-six.' + nume, titlu, bc, op, [r]);
co('consistency-start', 'the proof starts at another root than the old head', { op: 'set', path: ['proof', 'firstRoot'], value: altHex(cons.firstRoot) }, 'audittree.consistency-start');
co('consistency-end', 'the proof ends at another root than the new head', { op: 'set', path: ['proof', 'secondRoot'], value: altHex(cons.secondRoot) }, 'audittree.consistency-end');
co('consistency', 'one hash of the consistency path changed', { op: 'set', path: ['proof', 'path', 0], value: altHex(cons.path[0]) }, 'audittree.consistency'); }
// (H) an agent's signed ledger (agents): four entries of one fresh agent, verified as a stranger would
{ const GK = Object.keys(HARTA).filter((r) => r.startsWith('agents.')); const G = P.agentLedger; const bg = 'agent-ledger/four-entries.valid'; const L0 = G.ledger;
const altHex = (h) => h.slice(0, -1) + (h.endsWith('0') ? '1' : '0'); const NA = { integrity: 'NOT_MEASURED', authenticity: 'FAILED' }, NI = { authenticity: 'NOT_MEASURED' };
valid(bg, 'agent-ledger', 'the ledger of an agent: a tool call, a payment, a payment refused above the limit, a tool call', 'producer (agents ledger), one agent key made and discarded at generation', { ledger: L0, policy: G.policy }, { exercises: GK, levels: { authenticity: 'PASSED' } });
const ag = (nume, titlu, op, r, o = {}) => invalid('agent-ledger/four-entries.' + nume, titlu, bg, op, [r], { levels: ['agents.key', 'agents.identity', 'agents.signature'].includes(r) ? NA : NI, ...o });
ag('ledger-form', 'the entries are not a list', { op: 'set', path: ['ledger', 'entries'], value: 'none' }, 'agents.ledger-form');
ag('policy', 'the verifier pins another policy hash than the policy given', { op: 'add', path: ['policyHash'], value: '0x' + 'ab'.repeat(32) }, 'agents.policy');
ag('other-policy', 'the ledger names another policy', { op: 'set', path: ['ledger', 'policyHash'], value: altHex(L0.policyHash) }, 'agents.other-policy');
ag('session', 'the session is not the one derived from the agent and the policy', { op: 'set', path: ['ledger', 'session'], value: altHex(L0.session) }, 'agents.session');
ag('key', 'the public key is not a key', { op: 'set', path: ['ledger', 'publicKeyPem'], value: 'not a key' }, 'agents.key');
ag('key-classical', 'a ledger whose agent identity is an Ed25519 key: the id is derived from it and every entry is signed by it', null, 'agents.key', { producer: { note: 'the agent\'s identity key is a classical key (made and discarded at generation)', input: { ledger: G.classical.ledger, policy: G.classical.policy }, changed: [['ledger'], ['policy']] } });
{ const x = 'aere-agent:' + '11'.repeat(20); ag('identity', 'the ledger names an agent id that its key does not derive (with the session of that id)', null, 'agents.identity', { producer: { note: 'the ledger claims another agent id, and the session derived from it', input: { ledger: { ...clona(L0), agentId: x, session: sessionId(x, L0.policyHash) }, policy: G.policy }, changed: [['ledger', 'agentId'], ['ledger', 'session']] } }); }
ag('anchor', 'an anchor that names no entry of this ledger', { op: 'add', path: ['anchors'], value: [{ seq: 99, hash: L0.entries[0].hash, at: G.t0 }] }, 'agents.anchor');
ag('seq', 'an entry carries another sequence number', { op: 'set', path: ['ledger', 'entries', 1, 'seq'], value: 5 }, 'agents.seq');
ag('chain', 'an entry does not link the one before it', { op: 'set', path: ['ledger', 'entries', 1, 'prev'], value: altHex(L0.entries[1].prev) }, 'agents.chain');
ag('body', 'the body of an entry names another session than its ledger', { op: 'set', path: ['ledger', 'entries', 1, 'body', 'session'], value: altHex(L0.session) }, 'agents.body');
ag('signature', 'the signature of an entry has one character changed', { op: 'set', path: ['ledger', 'entries', 1, 'signature'], value: (L0.entries[1].signature[0] === 'A' ? 'B' : 'A') + L0.entries[1].signature.slice(1) }, 'agents.signature');
ag('hash', 'the hash of the last entry does not reproduce', { op: 'set', path: ['ledger', 'entries', 3, 'hash'], value: altHex(L0.entries[3].hash) }, 'agents.hash');
ag('time', 'the verifier\'s clock is before the entries: they are from its future', { op: 'add', path: ['maxTime'], value: G.t0 - 1000 }, 'agents.time');
const al4 = (nume, titlu, l, r, nota) => ag(nume, titlu, null, r, { producer: { note: nota, input: { ledger: l, policy: G.policy }, changed: [['ledger', 'entries', 3]] } });
al4('approvals', 'the fourth entry carries an empty approvals list', G.approvalsEmpty, 'agents.approvals', 'the agent signed an entry with an approvals field that is an empty list');
al4('decision', 'the fourth entry writes a refusal for a payment the policy allows', G.falseDecision, 'agents.decision', 'the agent signed an entry whose decision is not the one the policy gives');
al4('revocation', 'the fourth entry is a revocation entry that carries no revocation', G.revocationWithout, 'agents.revocation', 'the agent signed a revocation entry without the owner\'s revocation'); }
// (I) a presentation of a post-quantum credential (identity): judged with what the verifier brings (audience, nonce, clock, trusted
// issuers, status lists, revocations). One credential, shown by its holder and by a session key at the end of a delegation chain
{ const IK = Object.keys(HARTA).filter((r) => r.startsWith('identity.')); const X = P.identity; const A = 'identity-presentation'; const F = X.forged;
const intrare = (prez, o = {}) => ({ presentation: prez, audience: X.audience, nonce: X.nonce, now: X.now, trustedIssuers: X.trusted, statusLists: [X.lists.clean], ...o });
const AP = { authenticity: 'PASSED' }, OPRIT = { authenticity: 'NOT_MEASURED' }, NI = { integrity: 'NOT_MEASURED' }; const schimba = (c) => (c[0] === 'A' ? 'B' : 'A') + c.slice(1);
const src = 'producers (identity: issueCredential, createStatusList, delegate, present), six hybrid key pairs made and discarded at generation';
const bd = 'identity-presentation/direct.valid', bl = 'identity-presentation/delegated.valid';
valid(bd, A, 'a holder shows two of three disclosable claims to a verifier that brings its audience, its nonce, its clock, the issuer it trusts and the issuer\'s current status list', src, intrare(X.direct), { exercises: IK, levels: AP });
valid(bl, A, 'the same credential shown by a session key: the holder delegated to a phone, the phone to the session key for ten minutes and one claim', src, intrare(X.delegated), { exercises: IK, levels: AP });
// what the verifier did not bring: nothing fails, and the verdict is not VALID
const fara = (nume, titlu, baza, op, levels) => valid('identity-presentation/' + nume, A, titlu, src, aplica(V.find((x) => x.id === baza).input, op), { exercises: IK, verdict: 'PARTIAL', levels: { ...AP, ...levels }, base: baza, mutation: op });
fara('direct.no-audience.partial', 'the verifier gives no audience: a presentation made for another verifier would be accepted, so this one is not VALID', bd, { op: 'remove', path: ['audience'] }, NI);
fara('direct.no-nonce.partial', 'the verifier gives no nonce: an old presentation could be replayed', bd, { op: 'remove', path: ['nonce'] }, NI);
fara('direct.no-trusted-issuers.partial', 'the verifier names no issuer it trusts: anyone can issue a credential with their own keys', bd, { op: 'remove', path: ['trustedIssuers'] }, { authenticity: 'NOT_MEASURED' });
fara('direct.no-status-list.partial', 'the credential names a status list and the verifier was not handed it: a revocation cannot be seen', bd, { op: 'remove', path: ['statusLists'] }, NI);
fara('direct.status-list-other-issuer.partial', 'the list handed has the right id and another issuer\'s signature (and revokes): ignored, the status is not read', bd, { op: 'set', path: ['statusLists', 0], value: X.lists.otherIssuer }, NI);
fara('direct.status-list-expired.partial', 'the issuer\'s list handed is no longer valid on the verifier\'s clock: the status is not read', bd, { op: 'set', path: ['statusLists', 0], value: X.lists.expired }, NI);
// revocations that do not take effect leave the delegated presentation VALID
const ramane = (nume, titlu, rev) => { const op = { op: 'add', path: ['revocations'], value: [rev] }; valid('identity-presentation/' + nume, A, titlu, src, aplica(V.find((x) => x.id === bl).input, op), { exercises: IK, levels: AP, base: bl, mutation: op }); };
ramane('delegated.revocation-by-stranger.valid', 'a revocation of the first link signed by a stranger is ignored', X.revocations.byStranger);
ramane('delegated.revocation-in-the-future.valid', 'a revocation by the holder dated a day ahead has not taken effect on the verifier\'s clock', X.revocations.inTheFuture);
// one operation on the direct presentation
const d = (nume, titlu, op, r, o = {}) => invalid('identity-presentation/direct.' + nume, titlu, bd, op, r, o); const sg = X.direct.signature;
d('form', 'the file is of another kind', { op: 'set', path: ['presentation', 'kind'], value: 'aere-credential' }, ['identity.form'], { levels: OPRIT });
d('form-null', 'the presentation is the JSON value null', { op: 'set', path: ['presentation'], value: null }, ['identity.form'], { levels: OPRIT });
d('form-credential', 'the credential inside is of another kind', { op: 'set', path: ['presentation', 'credential', 'statement', 'kind'], value: 'aere-status-list' }, ['identity.form'], { levels: OPRIT });
d('form-binding', 'the binding is of another kind', { op: 'set', path: ['presentation', 'binding', 'kind'], value: 'aere-delegation' }, ['identity.form'], { levels: OPRIT });
d('issuer-trusted', 'the verifier trusts another issuer', { op: 'set', path: ['trustedIssuers'], value: [X.strangerId] }, ['identity.issuer-trusted']);
d('credential-revoked', 'the issuer\'s current status list has the bit of this credential set', { op: 'set', path: ['statusLists', 0], value: X.lists.revoked }, ['identity.credential-revoked']);
d('credential-revoked-second-list', 'two current lists of the issuer, one of them revokes: a revocation is not lifted by another list', { op: 'add', path: ['statusLists', 1], value: X.lists.revoked }, ['identity.credential-revoked']);
d('status-list', 'the issuer signed a status list that does not decompress', { op: 'set', path: ['statusLists', 0], value: X.lists.unreadable }, ['identity.status-list']);
d('status-list-index', 'the issuer\'s list is shorter than the index the credential names', { op: 'set', path: ['statusLists', 0], value: X.lists.short }, ['identity.status-list']);
d('binding-disclosures-removed', 'a disclosure taken out after the presenter signed', { op: 'remove', path: ['presentation', 'disclosures', 0] }, ['identity.binding-disclosures']);
d('binding-disclosures-added', 'a disclosure the issuer signed, added after the presenter signed (the holder did not choose to show it)', { op: 'add', path: ['presentation', 'disclosures', 2], value: X.undisclosed }, ['identity.binding-disclosures']);
d('presentation-signature', 'the ML-DSA-65 half of the presenter\'s signature has one character changed', { op: 'set', path: ['presentation', 'signature', 'mldsa65'], value: schimba(sg.mldsa65) }, ['identity.presentation-signature']);
d('presentation-signature-ed25519', 'the Ed25519 half of the presenter\'s signature has one character changed', { op: 'set', path: ['presentation', 'signature', 'ed25519'], value: schimba(sg.ed25519) }, ['identity.presentation-signature']);
d('presentation-signature-no-ml-dsa', 'the ML-DSA-65 half of the presenter\'s signature removed: the classical half alone is not a signature here', { op: 'remove', path: ['presentation', 'signature', 'mldsa65'] }, ['identity.presentation-signature']);
d('presentation-signature-alg', 'the signature declares ed25519 alone', { op: 'set', path: ['presentation', 'signature', 'alg'], value: 'ed25519' }, ['identity.presentation-signature']);
d('audience', 'the presentation was made for this verifier and is shown to another', { op: 'set', path: ['audience'], value: 'https://another-verifier.example' }, ['identity.audience']);
d('nonce', 'the verifier gave another nonce (a replay)', { op: 'set', path: ['nonce'], value: 'n-another' }, ['identity.nonce']);
d('freshness', 'the verifier\'s clock is an hour after the presentation was made', { op: 'set', path: ['now'], value: X.later }, ['identity.freshness']);
d('clock-years-later', 'the verifier\'s clock is years later: the credential has expired and the presentation is old', { op: 'set', path: ['now'], value: X.muchLater }, ['identity.credential-window', 'identity.freshness']);
// one change at a producer: only who holds the key can make these
const p = (baza) => (nume, titlu, prez, r, nota, o = {}) => invalid(`${baza.replace(/\.valid$/, '')}.${nume}`, titlu, baza, null, r, { levels: o.levels, producer: { note: nota, input: intrare(prez, o.input || {}), changed: [['presentation'], ...(o.changed || [])] } });
const pd = p(bd), pl = p(bl);
pd('issuer-id-impostor', 'an impostor issues the credential with its own keys under the id of the issuer the verifier trusts', F.issuerImpostor, ['identity.issuer-id'], 'another issuer wrote the trusted issuer\'s id beside its own keys and signed with them (this credential names no status list)');
pd('issuer-classical-key', 'the issuer\'s "ML-DSA-65" key is an Ed25519 key, the id is the hash of those keys and both halves of the signature are Ed25519: a classical key is not a post-quantum one because of the field it sits in', F.issuerClassicalKey.presentation, ['identity.credential-signature', 'identity.issuer-id'],
'an issuer with two Ed25519 keys (made and discarded at generation) put the second in the mldsa65 field, derived its id with the published formula and signed with both', { input: { trustedIssuers: [F.issuerClassicalKey.issuerId] }, changed: [['trustedIssuers']] });
pd('holder-id', 'the credential and the presenter name a holder id that the holder keys do not derive', F.holderId, ['identity.holder-id'], 'the issuer signed another holder id beside the holder\'s keys, and the holder presented under that id');
pd('credential-signature', 'the ML-DSA-65 half of the issuer\'s signature has one character changed, and the holder presents the credential so', F.credentialSignatureMlDsa, ['identity.credential-signature'], 'the holder presented a credential whose issuer signature was changed (ML-DSA-65 half)');
pd('credential-signature-ed25519', 'the Ed25519 half of the issuer\'s signature has one character changed', F.credentialSignatureEd25519, ['identity.credential-signature'], 'the holder presented a credential whose issuer signature was changed (Ed25519 half)');
pd('credential-signature-claim-edited', 'the holder edited a plain claim of the credential and presents it', F.claimEdited, ['identity.credential-signature'], 'the holder changed the plain claim employer after issuance and signed a presentation of the changed credential');
pd('credential-window-expired', 'the credential expired the day before', F.expired, ['identity.credential-window'], 'the issuer issued the same claims valid until the day before the presentation');
pd('credential-window-not-yet', 'the credential is valid only from the next day', F.notYetValid, ['identity.credential-window'], 'the issuer issued the same claims valid from the day after the presentation');
pd('sd-distinct', 'the issuer signed the same digest twice', F.sdTwice, ['identity.sd-distinct'], 'the issuer signed a credential whose sd list repeats a digest');
pd('disclosure-readable', 'a disclosure with a salt of eight bytes among those shown', F.disclosureShortSalt, ['identity.disclosure-readable'], 'the holder added a disclosure with an eight-byte salt and signed for the list');
pd('disclosure-signed', 'a disclosure the holder made up (age_over_21), signed for by the holder and not by the issuer', F.disclosureFabricated, ['identity.disclosure-signed'], 'the holder added a disclosure whose digest the issuer never signed and signed for the list');
pd('disclosure-once', 'the same disclosure shown twice', F.disclosureTwice, ['identity.disclosure-once'], 'the holder listed one disclosure twice and signed for the list');
pd('disclosure-plain', 'the issuer signed a disclosure for a claim the credential also has in the clear, with another value', F.disclosureOverPlain, ['identity.disclosure-plain'], 'the issuer added to sd the digest of a disclosure named like the plain claim employer; the holder shows it');
pd('claim-name', 'the issuer signed a plain claim whose name is not allowed', F.claimName, ['identity.claim-name'], 'the issuer signed a credential with a plain claim named "bad name"');
pd('binding-credential', 'the presenter signed for another credential than the one shown', F.otherCredential, ['identity.binding-credential'], 'the holder signed a binding that names the hash of another credential');
pd('presenter', 'a stranger presents the holder\'s credential with the holder\'s disclosures, signed with the stranger\'s keys', F.stranger, ['identity.presenter'], 'someone who is not the holder made and signed the presentation');
pd('unreadable', 'the presenter signed a binding whose time is not a time', F.createdAt, ['identity.unreadable'], 'the holder signed a binding with createdAt "yesterday"', { levels: OPRIT });
// the delegated presentation: one operation
const l = (nume, titlu, op, r, o = {}) => invalid('identity-presentation/delegated.' + nume, titlu, bl, op, r, o);
l('delegation-revoked', 'the holder revoked the first link before the presentation', { op: 'add', path: ['revocations'], value: [X.revocations.byHolder] }, ['identity.delegation-revoked']);
l('delegation-revoked-by-giver', 'the phone revoked the link it gave to the session key', { op: 'add', path: ['revocations'], value: [X.revocations.byGiver] }, ['identity.delegation-revoked']);
l('chain-cut', 'the last link taken out after the session key signed: the chain is not the one signed, and the presenter is not its last delegate', { op: 'remove', path: ['presentation', 'delegations', 1] }, ['identity.binding-delegations', 'identity.presenter']);
// the delegated presentation: one change at a producer
pl('binding-delegations', 'the session key signed for no chain and shows one', F.chainUnsigned, ['identity.binding-delegations'], 'the delegate signed a binding with an empty delegation list and attached the chain');
pl('chain-length', 'a chain of nine links', F.chainNine, ['identity.chain-length'], 'the holder, the phone and the session key delegated to one another nine times', { levels: OPRIT });
pl('delegation-form', 'the only link is of another kind, signed so by the holder', F.linkForm, ['identity.delegation-form'], 'the holder signed a link of kind aere-delegation-v0 to the phone, and the phone presents', { levels: OPRIT });
pl('delegation-ids', 'the link and the presenter name a delegate id that the delegate keys do not derive', F.linkIds, ['identity.delegation-ids'], 'the holder signed another delegate id beside the phone\'s keys, and the phone presented under that id');
pl('delegation-from', 'a stranger delegates the holder\'s credential to the phone', F.linkFromStranger, ['identity.delegation-from'], 'someone who is not the holder gave the first link');
pl('delegation-parent', 'the second link names no parent', F.linkNoParent, ['identity.delegation-parent'], 'the phone gave the session key a link that does not name the link it comes from');
pl('delegation-signature', 'the ML-DSA-65 half of the link\'s signature has one character changed, and the phone presents the chain so', F.linkSignature, ['identity.delegation-signature'], 'the phone presented a link whose signature was changed (ML-DSA-65 half)');
pl('delegation-scope-field', 'the scope of the link has a field the verifier does not know', F.linkScopeUnknownField, ['identity.delegation-scope'], 'the holder signed a link whose scope carries an extra field');
pl('delegation-scope-unsorted', 'the scope of the link is not in its normal form', F.linkScopeUnsorted, ['identity.delegation-scope'], 'the holder signed a link whose claims are not sorted');
pl('delegation-window', 'the link expired an hour before the presentation', F.linkExpired, ['identity.delegation-window'], 'the holder gave a link valid from two hours to one hour before');
pl('delegation-depth-zero', 'the first link allows no further delegation and the phone delegated anyway', F.linkDepthZero, ['identity.delegation-depth', 'identity.delegation-narrows'], 'the holder gave the phone a link of depth 0; the phone signed a second link under it');
pl('delegation-depth-negative', 'the second link is given a negative depth, so that it "narrows" a first link of depth 0', F.linkDepthNegative, ['identity.delegation-depth'], 'the holder gave the phone a link of depth 0; the phone signed a second link of depth -1 under it');
pl('delegation-narrows', 'the phone widens the claims the holder allowed it', F.linkWidens, ['identity.delegation-narrows'], 'the phone signed a second link whose claims are "*"');
pl('delegation-credential', 'the link is for another credential', F.linkOtherCredential, ['identity.delegation-credential'], 'the holder gave a link scoped to another credential id');
pl('delegation-claims', 'the phone shows a claim outside the scope of its link', F.linkOtherClaims, ['identity.delegation-claims'], 'the holder gave a link for one claim; the phone disclosed two');
pl('delegation-audience', 'the link is for another verifier', F.linkOtherAudience, ['identity.delegation-audience'], 'the holder gave a link scoped to another audience'); }
// (E) a dataset: a record, a range answer, a consistency proof, an availability sample
const DS = P.dataset; const REC = ['dataset.form', 'dataset.commitment', 'dataset.field', 'dataset.inclusion']; const src = 'producer (verifiable-data), random salts, generated ' + P.at;
valid('dataset-record/r5.valid', 'dataset-record', 'one record against the commitment of version 2, two fields disclosed', src, { record: DS.record, commitment: DS.newer }, { exercises: REC });
const inr = (nume, titlu, op, r) => invalid('dataset-record/r5.' + nume, titlu, 'dataset-record/r5.valid', op, [r]);
const altHex = (h) => h.slice(0, -1) + (h.endsWith('0') ? '1' : '0');
inr('form', 'the field commitments are not an object', { op: 'set', path: ['record', 'c'], value: 'x' }, 'dataset.form');
inr('commitment', 'the record names another commitment', { op: 'set', path: ['record', 'commitmentHash'], value: altHex(DS.record.commitmentHash) }, 'dataset.commitment');
inr('field', 'a disclosed value changed after commitment', { op: 'set', path: ['record', 'disclosed', 'age', 'value'], value: DS.record.disclosed.age.value + 1 }, 'dataset.field');
inr('field-no-salt', 'a disclosed field shown without its salt', { op: 'remove', path: ['record', 'disclosed', 'age', 'salt'] }, 'dataset.field');
inr('inclusion', 'one hash of the log proof changed', { op: 'set', path: ['record', 'logProof', 'path', 0], value: altHex(DS.record.logProof.path[0]) }, 'dataset.inclusion');
const ANS = [...REC, 'dataset.index', 'dataset.range', 'dataset.order', 'dataset.completeness'];
if (DS.answer.rows.length < 4) throw new Error('the fresh dataset answer has under four rows; regenerate with --proaspat');
valid('dataset-answer/age-30-45.valid', 'dataset-answer', 'a range query on an indexed field: every row, and the two neighbours that prove nothing is missing', src, { answer: DS.answer, commitment: DS.newer }, { exercises: ANS });
const rasp = (nume, titlu, op, r) => invalid('dataset-answer/age-30-45.' + nume, titlu, 'dataset-answer/age-30-45.valid', op, [r]);
rasp('commitment', 'an answer that names another version than the commitment it is checked against', { op: 'set', path: ['answer', 'version'], value: DS.answer.version - 1 }, 'dataset.commitment');
rasp('index-size', 'the answer states another index size than the commitment', { op: 'set', path: ['answer', 'indexSize'], value: DS.answer.indexSize + 1 }, 'dataset.commitment');
rasp('index-undisclosed', 'a row that does not disclose the queried field', { op: 'remove', path: ['answer', 'rows', 1, 'disclosed', 'age'] }, 'dataset.index');
rasp('index', 'one hash of a row\'s index proof changed', { op: 'set', path: ['answer', 'rows', 1, 'indexProof', 'path', 0], value: altHex(DS.answer.rows[1].indexProof.path[0]) }, 'dataset.index');
rasp('range', 'the answer claims a narrower range than the rows it returns', { op: 'set', path: ['answer', 'to'], value: DS.answer.rows[0].disclosed.age.value }, 'dataset.range');
rasp('completeness', 'a row dropped from the middle of the run', { op: 'remove', path: ['answer', 'rows', 1] }, 'dataset.completeness');
{ // the two forgeries only the SERVER of an answer can make: a matching row withheld and shown as the neighbour that closes the run
const b = V.find((x) => x.id === 'dataset-answer/age-30-45.valid'); const vecin = (r) => ({ pos: r.pos, value: r.disclosed.age.value, i: r.i, recordLeaf: BAZA.frunzaInregistrare(r.id, r.c), indexProof: r.indexProof });
const dupa = clona(b.input); const ultima = dupa.answer.rows.pop(); dupa.answer.after = vecin(ultima);
invalid('dataset-answer/age-30-45.completeness-last', 'the last matching row withheld and shown as the neighbour after the run (its value is still in range)', 'dataset-answer/age-30-45.valid', null, ['dataset.completeness'], { producer: { note: 'the server dropped the last row and presented it as the neighbour after', input: dupa, changed: [['answer', 'rows', dupa.answer.rows.length], ['answer', 'after']] } });
const inainte = clona(b.input); const prima = inainte.answer.rows.shift(); inainte.answer.before = vecin(prima);
invalid('dataset-answer/age-30-45.completeness-first', 'the first matching row withheld and shown as the neighbour before the run', 'dataset-answer/age-30-45.valid', null, ['dataset.completeness'], { producer: { note: 'the server dropped the first row and presented it as the neighbour before', input: inainte, changed: [['answer', 'rows'], ['answer', 'before']] } }); }
{ // order sits under the index root: two publishers of the same two records, one builds the index sorted, the other not
const recs = [{ id: 'x', k: 'b', salt: '00'.repeat(16) }, { id: 'y', k: 'a', salt: '11'.repeat(16) }].map((r) => { const c = { k: BAZA.angajamentCamp('k', r.k, r.salt) }; return { ...r, c, leaf: BAZA.frunzaInregistrare(r.id, c) }; });
const log = merkleTree(recs.map((r) => r.leaf)); const dov = (p) => ({ index: p.index, treeSize: p.treeSize, path: p.path });
const publica = (ordine, nume) => { const idx = merkleTree(ordine.map((i) => BAZA.frunzaIndex('k', recs[i].k, i, recs[i].leaf)));
const c = { v: 1, format: BAZA.FORMAT, name: nume, version: 1, size: 2, logRoot: log.root(), createdAt: '2026-10-03T00:00:00.000Z', indexes: { k: { root: idx.root(), size: 2 } }, previous: null };
const rand = (pos) => { const i = ordine[pos]; return { pos, i, id: recs[i].id, c: recs[i].c, disclosed: { k: { value: recs[i].k, salt: recs[i].salt } }, logProof: dov(log.inclusionProof(i, 2)), indexProof: dov(idx.inclusionProof(pos, 2)) }; };
return { answer: { v: 1, kind: BAZA.KIND_RASPUNS, name: nume, version: 1, commitmentHash: BAZA.hashAngajament(c), field: 'k', from: 'a', to: 'b', indexSize: 2, rows: [rand(0), rand(1)], before: null, after: null }, commitment: c }; };
valid('dataset-answer/two-records.valid', 'dataset-answer', 'two records, the index built in sorted order', 'producer formulas (verifiable-data), fixed salts', publica([1, 0], 'two-records'), { exercises: ANS });
invalid('dataset-answer/two-records.order', 'the same two records from a publisher whose index is not sorted: every proof holds, the order does not', 'dataset-answer/two-records.valid', null, ['dataset.order'],
{ producer: { note: 'the publisher built the index in record order instead of sorted order; the index root, the commitment hash and the rows follow from that', input: publica([0, 1], 'two-records'), changed: [['commitment', 'indexes', 'k', 'root'], ['answer', 'commitmentHash'], ['answer', 'rows']] } }); }
valid('dataset-consistency/v1-v2.valid', 'dataset-consistency', 'version 1 is a prefix of version 2', src, { proof: DS.consistency, older: DS.older, newer: DS.newer }, { exercises: ['dataset.commitment', 'dataset.consistency'] });
invalid('dataset-consistency/v1-v2.commitment', 'the proof names another newer commitment', 'dataset-consistency/v1-v2.valid', { op: 'set', path: ['proof', 'to', 'commitmentHash'], value: altHex(DS.consistency.to.commitmentHash) }, ['dataset.commitment']);
invalid('dataset-consistency/v1-v2.consistency', 'one hash of the consistency path changed', 'dataset-consistency/v1-v2.valid', { op: 'set', path: ['proof', 'proof', 'path', 0], value: altHex(DS.consistency.proof.path[0]) }, ['dataset.consistency']);
valid('dataset-sample/four-of-sixteen.valid', 'dataset-sample', 'four positions drawn from a seed, each served and verified', src, { commitment: DS.newer, k: DS.sample.k, seed: DS.sample.seed, served: DS.sample.served }, { exercises: [...REC, 'dataset.sample'] });
invalid('dataset-sample/four-of-sixteen.sample', 'the publisher does not serve one of the sampled records', 'dataset-sample/four-of-sixteen.valid', { op: 'remove', path: ['served', Object.keys(DS.sample.served)[0]] }, ['dataset.sample']);
return V;
}
const text = (v) => JSON.stringify(v, null, 1) + '\n';
function fisiere(vectori) {
const out = new Map(); const reguli = {};
for (const v of vectori) { if (out.has(v.id + '.json')) throw new Error('two vectors with the id ' + v.id); out.set(v.id + '.json', text(v)); for (const r of v.expected.failed) (reguli[r] || (reguli[r] = [])).push(v.id); }
const artifacte = {}; for (const v of vectori) artifacte[v.artifact] = (artifacte[v.artifact] || 0) + 1;
const index = { v: 1, kind: 'aere-conformance-vector-index', count: vectori.length, artifacts: artifacte, offline: vectori.filter((v) => !v.requires.length).length, online: vectori.filter((v) => v.requires.length).length,
rules: Object.fromEntries(Object.keys(reguli).sort().map((r) => [r, reguli[r]])), vectors: vectori.map((v) => ({ id: v.id, artifact: v.artifact, verdict: v.expected.verdict, requires: v.requires, sha256: sha256(Buffer.from(out.get(v.id + '.json'), 'utf8')) })) };
out.set('INDEX.json', text(index)); return out;
}
const peDisc = (d, pre = '') => (fs.existsSync(d) ? fs.readdirSync(d, { withFileTypes: true }).flatMap((e) => (e.isDirectory() ? peDisc(path.join(d, e.name), pre + e.name + '/') : [pre + e.name])) : []);
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
const a = process.argv.slice(2);
if (a.includes('--proaspat')) await proaspat(a.includes('--tot'));
const out = fisiere(construieste());
if (a.includes('--verifica')) {
let dif = 0; for (const [f, t] of out) { const p = path.join(DIR, f); if (!fs.existsSync(p) || fs.readFileSync(p, 'utf8').replace(/\r\n/g, '\n') !== t) { dif++; console.log('DIFERIT: ' + f); } }
const straine = peDisc(DIR).filter((f) => !out.has(f)); if (straine.length) { dif += straine.length; console.log('STRAINE: ' + straine.join(', ')); }
console.log(dif ? `DIFERIT (${dif})` : `LA ZI (${out.size - 1} vectors + INDEX.json)`); process.exitCode = dif ? 1 : 0;
} else {
for (const f of peDisc(DIR)) if (!out.has(f)) fs.rmSync(path.join(DIR, f));
for (const [f, t] of out) { const p = path.join(DIR, f); fs.mkdirSync(path.dirname(p), { recursive: true }); fs.writeFileSync(p, t); }
const idx = JSON.parse(out.get('INDEX.json')); console.log(`written ${idx.count} vectors (${idx.offline} offline, ${idx.online} need testnet 28001): ` + Object.entries(idx.artifacts).map(([k, n]) => k + ' ' + n).join(', '));
}
}