#!/usr/bin/env node // selftest.js, the runnable proof that this toolkit really works, with NO live // RPC required. It: // 1. checks keccak256 against the empty-string NIST/Ethereum vector, // 2. re-derives the LIVE sample AerePQCAccount address from its real Falcon // key and asserts it equals the on-chain address (proves CREATE2 math), // 3. runs the scanner against the bundled REAL bytecode fixtures and asserts // the RED / YELLOW / GREEN classifications, // 4. runs a small migration-cost simulation. // Exits non-zero on any failure. import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; import { keccak256Hex, bytesToHex } from './lib/keccak.js'; import { predictPqcAccountAddress } from './lib/migrate.js'; import { scanBytecode } from './lib/scanner.js'; import { simulateMigration } from './lib/simulate.js'; import { encodeMigrateCalldata, encodeApproveCalldata, encodeTransferCalldata, encodeBalanceOfCalldata, buildMigrationTransactions, } from './lib/migrator.js'; import { buildReadinessReport } from './lib/readiness.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); let failures = 0; const ok = (name, cond, detail = '') => { console.log(` ${cond ? 'PASS' : 'FAIL'} ${name}${detail ? ' ' + detail : ''}`); if (!cond) failures++; }; console.log('Aere PQC migration toolkit, self test\n'); // 1. keccak256 correctness console.log('[1] keccak256 zero-dependency implementation'); const empty = keccak256Hex('0x'); ok('keccak256("") == c5d2460186f7233c...', empty === '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470', empty); // 2. CREATE2 address re-derivation against the LIVE sample account console.log('\n[2] CREATE2 account-address derivation (vs the live on-chain sample)'); // Datele de desfasurare se citesc din PROPRIA fixtura a trusei, nu de undeva din afara pachetului. // Pana pe 2026-08-17 se citeau prin `..` din arborele de dezvoltare, deci selftest trecea la noi si // CADEA cu ENOENT la orice strain care clona depozitul: exact primul lucru pe care il face cineva // care ne verifica. Gasit ruland o clona proaspata ca un strain, nu citind sursa. const CALE_DEP = join(__dirname, 'fixtures', 'pqc-account.json'); const dep = JSON.parse(readFileSync(CALE_DEP, 'utf8')); const sampleKey = dep.sampleAccount.falconPubKey; const expected = dep.sampleAccount.address; const derived = predictPqcAccountAddress({ falconPubKey: sampleKey, salt: dep.sampleAccount.salt, factory: dep.factory, initCodeHash: dep.accountInitCodeHash, }); ok(`predictPqcAccountAddress == ${expected}`, derived.toLowerCase() === expected.toLowerCase(), derived); // 3. scanner classifications against REAL bytecode fixtures console.log('\n[3] scanner on bundled REAL bytecode fixtures'); const fx = (name) => readFileSync(join(__dirname, 'fixtures', name + '.hex'), 'utf8').trim(); const attest = scanBytecode('fixture:AerePQCAttestation', fx('AerePQCAttestation')); ok('AerePQCAttestation => GREEN (native PQC precompiles)', attest.readiness === 'GREEN', attest.readiness + ' [' + attest.signals.pqcLivePrecompiles.map((p) => p.address).join(',') + ']'); const txAcct = scanBytecode('fixture:AerePQCTxAccount', fx('AerePQCTxAccount')); ok('AerePQCTxAccount => GREEN (native PQC precompiles)', txAcct.readiness === 'GREEN', txAcct.readiness + ' [' + txAcct.signals.pqcLivePrecompiles.map((p) => p.address).join(',') + ']'); // AereHybridAuth uses ecrecover but delegates Falcon to the SOLIDITY verifier // (a contract, not the native precompile), so bytecode scanning reads it RED. // This is the documented honest limitation, asserted here so it cannot regress. const hybrid = scanBytecode('fixture:AereHybridAuth', fx('AereHybridAuth')); ok('AereHybridAuth => RED (delegates Falcon to Solidity verifier; scope limit)', hybrid.readiness === 'RED', hybrid.readiness); const falconV = scanBytecode('fixture:AereFalcon512Verifier', fx('AereFalcon512Verifier')); ok('AereFalcon512Verifier => RED (heavy math; 0x0100 constants are literals, not P-256)', falconV.readiness === 'RED' && !falconV.signals.p256, falconV.readiness); // synthetic hybrid: real EVM ops calling BOTH 0x01 (ecrecover) and 0x0AE1 // (Falcon-512) via STATICCALL. Proves the YELLOW path deterministically. // Sequence per call: PUSH1 retSize, PUSH1 retOff, PUSH1 argsSize, PUSH1 argsOff, // PUSH2/PUSH1 addr, GAS, STATICCALL, POP. const synthetic = '0x' + '6020' + '6000' + '6040' + '6000' + '6001' + '5a' + 'fa' + '50' + // staticcall 0x01 (ecrecover) '6020' + '6000' + '6040' + '6000' + '610ae1' + '5a' + 'fa' + '50'; // staticcall 0x0ae1 (Falcon-512) const synth = scanBytecode('synthetic:hybrid', synthetic); ok('synthetic 0x01 + 0x0AE1 => YELLOW (hybrid)', synth.readiness === 'YELLOW', synth.readiness + ' pqc=' + synth.signals.pqcLivePrecompiles.length + ' ecrecover=' + (synth.signals.ecrecover ? 'yes' : 'no')); // EOA path const eoa = scanBytecode('0x0000000000000000000000000000000000000001', '0x'); ok('empty code => RED (EOA)', eoa.readiness === 'RED' && eoa.kind === 'eoa', eoa.kind); // 4. simulation sanity console.log('\n[4] migration cost simulation'); const sim = simulateMigration( [{ scheme: 'falcon512', authsPerAccount: 1 }, { scheme: 'hybrid', authsPerAccount: 2 }], { gweiPrice: 1 }, ); ok('simulation totals are positive and finite', sim.totals.totalGas > 0 && Number.isFinite(sim.totals.estimatedAere), `${sim.totals.totalGas.toLocaleString()} gas, ${sim.totals.estimatedAere.toFixed(6)} AERE`); // 5. ABI calldata builders vs ethers v6 ground truth (hardcoded expected values, // each independently generated by ethers 6.16.0; see the toolkit README). This // proves the zero-dependency encoder emits byte-identical calldata to a full ABI // library, so what a user is handed to sign is correct. console.log('\n[5] migration SDK calldata (vs ethers v6 ground truth)'); const dest = '0xa42a5e7F72E46BadC11367650Ec34D676194326f'; const tokenA = '0x1111111111111111111111111111111111111111'; const tokenB = '0x2222222222222222222222222222222222222222'; const EXP = { migrate: '0xe015b041000000000000000000000000a42a5e7f72e46badc11367650ec34d676194326f000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0', approve: '0x095ea7b3000000000000000000000000a42a5e7f72e46badc11367650ec34d676194326f00000000000000000000000000000000000000000000000000000000000003e8', transfer: '0xa9059cbb000000000000000000000000a42a5e7f72e46badc11367650ec34d676194326f00000000000000000000000000000000000000000000000000000000000003e8', balanceOf: '0x70a08231000000000000000000000000a42a5e7f72e46badc11367650ec34d676194326f', }; const gotMigrate = encodeMigrateCalldata({ destination: dest, tokens: [tokenA, tokenB], amounts: [1000n, 2000n], moveNative: true }); ok('encodeMigrateCalldata == ethers migrate(...)', gotMigrate.toLowerCase() === EXP.migrate, `${(gotMigrate.length - 2) / 2} bytes`); ok('encodeApproveCalldata == ethers approve(...)', encodeApproveCalldata(dest, 1000n).toLowerCase() === EXP.approve); ok('encodeTransferCalldata == ethers transfer(...)', encodeTransferCalldata(dest, 1000n).toLowerCase() === EXP.transfer); ok('encodeBalanceOfCalldata == ethers balanceOf(...)', encodeBalanceOfCalldata(dest).toLowerCase() === EXP.balanceOf); // 6. buildMigrationTransactions: unsigned, correct target, no signature anywhere. console.log('\n[6] unsigned migration transaction plan'); const plan = buildMigrationTransactions({ path: 'direct', eoa: '0x000000000000000000000000000000000000dEaD', falconPubKey: sampleKey, tokens: [{ token: tokenA, amountWei: 5n }], nativeWei: 100n, }); ok('plan.signed === false (nothing signed)', plan.signed === false); ok('plan.target matches CREATE2 derivation', plan.target.toLowerCase() === expected.toLowerCase(), plan.target); ok('every tx object is unsigned (signed:false, no r/s/v/signature field)', plan.transactions.length > 0 && plan.transactions.every((t) => t.signed === false && !('signature' in t.tx) && !('r' in t.tx)), `${plan.transactions.length} txs`); ok('direct path builds deploy + erc20 transfer + native send (3 steps)', plan.transactions.length === 3 && plan.transactions[0].kind === 'createAccount' && plan.transactions[1].kind === 'erc20Transfer' && plan.transactions[2].kind === 'nativeTransfer', plan.transactions.map((t) => t.kind).join(',')); let migratorThrew = false; try { buildMigrationTransactions({ path: 'migrator', eoa: '0x000000000000000000000000000000000000dEaD', falconPubKey: sampleKey, tokens: [{ token: tokenA, amountWei: 5n }] }); } catch { migratorThrew = true; } ok('migrator path without an explicit migrator address is refused (not deployed)', migratorThrew); // 7. readiness report composes cited gas + honest asset-move estimate. console.log('\n[7] quantum-readiness report'); const rr = buildReadinessReport({ scan: { address: dest, kind: 'eoa', readiness: 'RED', reason: 'EOA' }, assets: { native: { symbol: 'AERE', balanceWei: '100', needsMove: true }, tokens: [{ token: tokenA, symbol: 'TKA', balance: '5', needsMove: true }], movable: 2 }, scheme: 'falcon512_solidity', path: 'direct', projectedAuths: 1, gwei: 1, }); ok('readiness one-time gas = deploy + native + erc20 (positive, finite)', rr.gas.oneTimeTotal > rr.gas.deploy && Number.isFinite(rr.cost.oneTimeAere), `${rr.gas.oneTimeTotal.toLocaleString()} gas one-time`); ok('readiness ongoing per-auth uses the CITED deployed-account figure (10,278,313)', rr.gas.perAuth === 10278313, `${rr.gas.perAuth.toLocaleString()} gas/auth`); ok('readiness counts 2 movable assets', rr.assetsToMove.count === 2); console.log(`\n${failures === 0 ? 'ALL PASS' : failures + ' FAILURE(S)'}`); process.exit(failures === 0 ? 0 : 1);