76 lines
7.1 KiB
JavaScript
76 lines
7.1 KiB
JavaScript
'use strict';
|
|
// Proba "Proof of everything": pentru FIECARE fel construieste un plic, il verifica cu ACELASI verificator AIP-23 (zero cod nou), si
|
|
// controale negative: continut atins dupa hash -> INVALID; camp obligatoriu lipsa -> eroare la constructie; niciun continut brut in plic.
|
|
// node proba-proof-kinds.mjs -> 0 toate cum trebuia, 1 altfel
|
|
|
|
import fs from 'node:fs'; import crypto from 'node:crypto'; import os from 'node:os'; import path from 'node:path';
|
|
import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url';
|
|
import { buildProof, KINDS } from './proof-kinds.mjs';
|
|
|
|
const AICI = path.dirname(fileURLToPath(import.meta.url));
|
|
const VERIFY = process.env.AERE_VERIFY_PROOF ? path.resolve(process.env.AERE_VERIFY_PROOF) : path.resolve(AICI, '..', 'aere-proof-protocol', 'verify.mjs');
|
|
if (!fs.existsSync(VERIFY)) { console.log(`NEMASURAT: verificatorul AIP-23 nu e la ${VERIFY}; dati AERE_VERIFY_PROOF (de ex. verify-proof.mjs din aere-node/tools)`); process.exit(2); }
|
|
const T = fs.mkdtempSync(path.join(os.tmpdir(), 'pk-'));
|
|
let rele = 0; const cer = (n, c) => { console.log(` [${c ? 'OK ' : 'RAU '}] ${n}`); if (!c) rele++; };
|
|
function verdict(plicPath) { try { return JSON.parse(execFileSync(process.execPath, [VERIFY, plicPath, '--json'], { encoding: 'utf8' })).verdict; } catch (e) { try { return JSON.parse((e.stdout || '')).verdict; } catch { return '?'; } } }
|
|
|
|
// intrari de proba pentru fiecare fel (continut brut, ca sa verific ca nu se scurge)
|
|
const BRUT = 'CONTINUT-BRUT-BRUT-42';
|
|
const INTRARI = {
|
|
data: { name: 'raport.csv', content: BRUT, createdAt: '2026-09-26T09:00:00Z' },
|
|
execution: { program: 'aere-node', input: BRUT, output: BRUT + 'o', exitCode: 0, createdAt: '2026-09-26T09:00:00Z' },
|
|
identity: { subjectId: 'agent-1', publicKey: BRUT, method: 'ml-dsa-65', createdAt: '2026-09-26T09:00:00Z' },
|
|
compliance: { subject: 'org-x', policy: 'pq-ready', result: 'pass', evidence: BRUT, createdAt: '2026-09-26T09:00:00Z' },
|
|
runtime: { host: 'h1', artifactContent: BRUT, attested: BRUT, matches: true, createdAt: '2026-09-26T09:00:00Z' },
|
|
location: { subject: 'srv-eu', region: 'eu-central', evidence: BRUT, createdAt: '2026-09-26T09:00:00Z' },
|
|
device: { deviceId: 'dev-9', attestation: BRUT, publicKey: BRUT, posture: 'secure-boot', createdAt: '2026-09-26T09:00:00Z' },
|
|
payment: { from: '0xa', to: '0xb', amount: '100', asset: 'AERE', tx: BRUT, createdAt: '2026-09-26T09:00:00Z' },
|
|
ownership: { owner: '0xowner', assetId: 'nft-7', asset: BRUT, createdAt: '2026-09-26T09:00:00Z' },
|
|
time: { subject: BRUT, source: 'aere-anchor', at: '2026-09-26T09:00:00Z', createdAt: '2026-09-26T09:00:00Z' },
|
|
block: { blockHash: '0x' + 'ab'.repeat(32), stateRoot: '0x' + 'cd'.repeat(32), anchorHeight: 20255488, certificateDigest: '0x' + 'ef'.repeat(32), createdAt: '2026-09-26T09:00:00Z' },
|
|
authorization: { grantor: 'org-x', grantee: 'agent-7', scope: 'payments:send<=100', policy: BRUT, expiresAt: '2026-12-31T00:00:00Z', createdAt: '2026-09-28T09:00:00Z' },
|
|
settlement: { chainId: 2800, txHash: '0x' + '12'.repeat(32), blockHash: '0x' + '34'.repeat(32), from: '0xa', to: '0xb', amount: '100', asset: 'AERE', instruction: BRUT, createdAt: '2026-09-28T09:00:00Z' },
|
|
provenance: { subject: BRUT, parents: [BRUT + '1', BRUT + '2'], process: BRUT + 'p', actor: 'build-bot', createdAt: '2026-09-28T09:00:00Z' },
|
|
};
|
|
|
|
try {
|
|
cer('schema acopera cele 14 feluri (10 + bloc + autorizare, decontare, provenienta)', KINDS.length >= 14 && ['authorization', 'settlement', 'provenance'].every((k) => KINDS.includes(k)));
|
|
for (const k of KINDS) {
|
|
// fiecare fel se judeca separat: un fel care nu se mai poate construi e un RAU numit, nu o exceptie care opreste proba (2026-09-28)
|
|
let plic; try { plic = buildProof(k, INTRARI[k]); } catch (e) { cer(`${k}: constructia a cazut (${e.message})`, false); continue; }
|
|
const f = path.join(T, k + '.json'); fs.writeFileSync(f, JSON.stringify(plic, null, 1));
|
|
const v = verdict(f);
|
|
const faraBrut = !JSON.stringify(plic).includes(BRUT);
|
|
cer(`${k}: verificatorul AIP-23 il valideaza si nu contine continut brut`, v === 'VALID' && faraBrut);
|
|
}
|
|
// CONTROL NEGATIV 1: statement atins dupa hash -> INVALID (pe 'data')
|
|
const p = buildProof('data', INTRARI.data); p.statement.name = 'ALTCEVA';
|
|
const fr = path.join(T, 'rau.json'); fs.writeFileSync(fr, JSON.stringify(p, null, 1));
|
|
cer('CONTROL: statement schimbat dupa hash -> INVALID', verdict(fr) === 'INVALID');
|
|
// CONTROL NEGATIV 2: camp obligatoriu lipsa -> eroare la constructie
|
|
let aAruncat = false; try { buildProof('data', { name: 'x', createdAt: '2026-09-26T09:00:00Z' }); } catch { aAruncat = true; }
|
|
cer('CONTROL: camp obligatoriu lipsa (sha256) -> eroare la constructie', aAruncat);
|
|
// CONTROL NEGATIV 3: fel necunoscut -> eroare
|
|
let aAruncat2 = false; try { buildProof('inexistent', { createdAt: '2026-09-26T09:00:00Z' }); } catch { aAruncat2 = true; }
|
|
cer('CONTROL: fel necunoscut -> eroare', aAruncat2);
|
|
// 2026-09-28: felurile noi isi refuza formele gresite la constructie, nu produc un plic gresit
|
|
const arunca = (f) => { try { f(); return false; } catch { return true; } };
|
|
cer('CONTROL: decontare cu txHash care nu e hash de 32 de octeti -> eroare', arunca(() => buildProof('settlement', { ...INTRARI.settlement, txHash: '0x1234' })));
|
|
cer('CONTROL: provenienta cu lista de parinti goala -> eroare', arunca(() => buildProof('provenance', { ...INTRARI.provenance, parents: [] })));
|
|
cer('CONTROL: autorizare fara scope -> eroare', arunca(() => buildProof('authorization', { ...INTRARI.authorization, scope: undefined })));
|
|
const pv = buildProof('provenance', INTRARI.provenance);
|
|
cer('provenienta: fiecare parinte e digestul continutului lui, in ordine', pv.statement.parents.length === 2 && pv.statement.parents[0] === '0x' + crypto.createHash('sha256').update(BRUT + '1', 'utf8').digest('hex'));
|
|
// OCTETII unui Buffer (2026-09-27): digestul continutului dat ca Buffer = sha256 al octetilor (cel pe care il reface sha256sum pe
|
|
// fisier) = digestul aceluiasi continut dat ca sir. Pana azi un Buffer se hashuia ca JSON {"type":"Buffer",...}.
|
|
const oct = Buffer.from('ARTEFACT-DESFASURAT-\u0000\u00ff', 'latin1');
|
|
const asteptat = '0x' + crypto.createHash('sha256').update(oct).digest('hex');
|
|
const pb = buildProof('data', { name: 'a', content: oct, createdAt: '2026-09-26T09:00:00Z' });
|
|
const pu = buildProof('data', { name: 'a', content: new Uint8Array(oct), createdAt: '2026-09-26T09:00:00Z' });
|
|
const ps = buildProof('data', { name: 'a', content: 'abc', createdAt: '2026-09-26T09:00:00Z' });
|
|
cer('Buffer/Uint8Array: digestul = sha256 al octetilor (reproductibil cu sha256sum)', pb.statement.sha256 === asteptat && pu.statement.sha256 === asteptat);
|
|
cer('sirurile raman ca inainte (vectorii publicati neschimbati)', ps.statement.sha256 === '0x' + crypto.createHash('sha256').update('abc', 'utf8').digest('hex'));
|
|
} finally { fs.rmSync(T, { recursive: true, force: true }); }
|
|
const total = KINDS.length + 10;
|
|
console.log(`\nProof of everything: ${total - rele}/${total} cum trebuia (${KINDS.length} feluri + 6 controale negative + acoperire + Buffer + parinti)`);
|
|
process.exit(rele ? 1 : 0);
|