ai-trust/ links six existing proofs (agent identity, model artifact attestation, host runtime record, policy and signed ledger,
Proof of AI envelope, on-chain witness) into one bundle judged by one verifier that checks only the links; 13/13 in the lab,
16/16 live on testnet 28001 (ledger head notarized). proof-of-ai/ is the AIP-23 envelope builder it uses. verifiable-data/
publishes append-only versions with an RFC 9162 root and a sorted index per field, range and equality queries proven correct
and complete, selective disclosure per field, availability by sampling, and the AIP-23 data envelope notarized (version 2 on
testnet 28001). agents/agent-ancora.mjs gains notarizeEnvelope({kind}), the general form of notarizeHead. Each README says what
is not built: zero-knowledge queries need a prover and are not here. No third party has reviewed any of this.
55 lines
5.2 KiB
JavaScript
55 lines
5.2 KiB
JavaScript
#!/usr/bin/env node
|
|
// verifica.mjs: the reader's side of a verifiable dataset, without the data (roadmap point 20). Everything is judged against a
|
|
// COMMITMENT (a version's JSON) and prints VALID / INVALID with the reasons; exit 0 VALID, 1 INVALID, 2 could not measure.
|
|
// node verifica.mjs raspuns <answer.json> --angajament <c.json> a query answer: correct, complete, in order
|
|
// node verifica.mjs inregistrare <record.json> --angajament <c.json> one record with its proof
|
|
// node verifica.mjs consistenta <proof.json> --vechi <c1.json> --nou <c2.json> the newer version only appended
|
|
// node verifica.mjs disponibilitate --url <http://host:port/v1/vd/name> --angajament <c.json> [--esantioane 16] [--seed <hex>]
|
|
// random records fetched and verified (retrievability)
|
|
// node verifica.mjs angajament <c.json> --plic <env.json> [--verify-proof <verify-proof.mjs>] [--rpc URL --chain 28001]
|
|
// the AIP-23 envelope is this commitment's; with --rpc,
|
|
// its notarization under a post-quantum certified anchor
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { spawn } from 'node:child_process';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { verificaRaspuns, verificaInregistrare, verificaConsistentaVersiuni, verificaPlicAngajament, esantioneaza, hashAngajament } from './baza.mjs';
|
|
|
|
const AICI = path.dirname(fileURLToPath(import.meta.url));
|
|
const a = process.argv.slice(2); const cmd = a[0];
|
|
const opt = (k, d = null) => { const i = a.indexOf(k); return i >= 0 && i + 1 < a.length ? a[i + 1] : d; };
|
|
const citeste = (f) => JSON.parse(fs.readFileSync(f, 'utf8'));
|
|
const iesi = (verdict, motive = [], extra = '') => { console.log(`${verdict}${extra ? ' ' + extra : ''}${motive.length ? '\n ' + motive.join('\n ') : ''}`); process.exitCode = verdict === 'VALID' ? 0 : verdict === 'INVALID' ? 1 : 2; };
|
|
const ruleaza = (verifyProof, envFile, { rpc, chain }) => new Promise((ok) => {
|
|
const args = [verifyProof, envFile, '--json', ...(rpc ? ['--rpc', rpc] : []), ...(chain ? ['--chain', String(chain)] : [])];
|
|
const c = spawn(process.execPath, args); let out = ''; c.stdout.on('data', (d) => { out += d; }); c.stderr.on('data', () => {});
|
|
const ceas = setTimeout(() => c.kill(), 300000); c.on('error', () => { clearTimeout(ceas); ok(null); }); c.on('close', () => { clearTimeout(ceas); try { ok(JSON.parse(out)); } catch { ok(null); } });
|
|
});
|
|
|
|
async function main() {
|
|
if (cmd === 'raspuns') { const r = verificaRaspuns(citeste(a[1]), citeste(opt('--angajament'))); return iesi(r.verdict, r.motive, `(${r.rows} rows)`); }
|
|
if (cmd === 'inregistrare') { const r = verificaInregistrare(citeste(a[1]), citeste(opt('--angajament'))); return iesi(r.ok ? 'VALID' : 'INVALID', r.motive); }
|
|
if (cmd === 'consistenta') { const r = verificaConsistentaVersiuni(citeste(a[1]), citeste(opt('--vechi')), citeste(opt('--nou'))); return iesi(r.ok ? 'VALID' : 'INVALID', r.motive); }
|
|
if (cmd === 'disponibilitate') {
|
|
const url = opt('--url'); const c = citeste(opt('--angajament')); if (!url) throw new Error('--url is required');
|
|
const ia = async (u) => { const r = await fetch(u, { headers: { accept: 'application/json' }, signal: AbortSignal.timeout(20000) }); if (!r.ok) return null; return r.json(); };
|
|
const r = await esantioneaza({ url, commitment: c, k: Number(opt('--esantioane', 16)), seed: opt('--seed', null), ia });
|
|
return iesi(r.ok ? 'VALID' : 'INVALID', r.motive, `(${r.verificate} of ${r.cerute} sampled records verified, seed ${r.seed}${r.lipsa.length ? '; not served: ' + r.lipsa.join(',') : ''})`);
|
|
}
|
|
if (cmd === 'angajament') {
|
|
const c = citeste(a[1]); const env = citeste(opt('--plic'));
|
|
if (!verificaPlicAngajament(env, c)) return iesi('INVALID', ['the envelope is not this commitment\'s (sha256/name differ, or not an aere-proof-of-data attestation)']);
|
|
const vp = opt('--verify-proof', process.env.AERE_VERIFY_PROOF || path.resolve(AICI, '..', '..', 'verificator-falcon', 'verify-proof.mjs'));
|
|
if (!fs.existsSync(vp)) return iesi('UNMEASURED', ['the AIP-23 verifier is not at ' + vp + ' (AERE_VERIFY_PROOF or --verify-proof)'], `commitment ${hashAngajament(c)} is the envelope's`);
|
|
const v = await ruleaza(vp, opt('--plic'), { rpc: opt('--rpc'), chain: opt('--chain') });
|
|
if (!v) return iesi('UNMEASURED', ['the verifier gave no JSON']);
|
|
const fin = (v.levels || []).find((l) => l.level === 'finality');
|
|
const extra = `envelope ${v.verdict}; finality ${fin ? fin.state + ': ' + String(fin.detail).slice(0, 160) : 'absent'}`;
|
|
if (v.verdict !== 'VALID') return iesi('INVALID', [], extra);
|
|
if (opt('--rpc') && !(fin && fin.state === 'PASSED')) return iesi(fin && fin.state === 'FAILED' ? 'INVALID' : 'UNMEASURED', [], extra);
|
|
return iesi('VALID', [], extra);
|
|
}
|
|
console.log('usage: verifica.mjs raspuns|inregistrare|consistenta|disponibilitate|angajament ... (see the header)'); process.exitCode = 2;
|
|
}
|
|
try { await main(); } catch (e) { iesi('UNMEASURED', [String(e.message).slice(0, 200)]); }
|