pqc-migration-toolkit/lib/scanner.js
Aere Network de9a79298c Aere PQC migration toolkit: measure an address quantum exposure from its bytecode
Zero dependencies, no account, no API. Every command takes --rpc, so it runs
against a node you operate and never needs ours. That is the point: an exposure
measurement you cannot re-run is an opinion with a logo on it.

Ships with two self-checks meant to be run by you, not just by us. The second,
proba-vocabular.mjs, exists because of a real defect found on 2026-08-16: the
scanner emits RED / YELLOW / GREEN, two downstream files each wrote their own
copy of that list, and both wrote AMBER, so a hybrid contract, exactly a client
who has already started migrating, was reported as unmeasurable. Both sides were
self-consistent, so nothing we had could see it. The vocabulary now has one
exported source, and the test walks the whole path with a negative control that
makes it able to fail.

The same scanner returns RED about our own contracts. See VERIFY-US.md.
2026-08-17 10:31:31 +03:00

63 lines
2.4 KiB
JavaScript

// scanner.js, the account-level readiness classifier. Ties the RPC fetch and
// the bytecode analysis together and produces the RED / YELLOW / GREEN report.
// Zero dependencies.
import { analyzeBytecode } from './bytecode.js';
import { hexToBytes } from './keccak.js';
import { getCode, getChainId } from './rpc.js';
const ADDR_RE = /^0x[0-9a-fA-F]{40}$/;
export function isValidAddress(a) {
return typeof a === 'string' && ADDR_RE.test(a);
}
/**
* Classify an EOA. An externally owned account is authenticated by a
* secp256k1 ECDSA key: quantum-vulnerable, and (unlike a contract) it CANNOT
* host post-quantum verification logic. Always RED. The migration path for an
* EOA is to move control to a PQC or hybrid smart account (see the migration
* SDK), optionally via EIP-7702 delegation.
*/
export function classifyEoa(address) {
return {
address,
kind: 'eoa',
readiness: 'RED',
reason: 'Externally owned account: authenticated by a secp256k1 ECDSA key, which Shor\'s algorithm breaks. An EOA holds no code, so it cannot verify a post-quantum signature itself.',
signals: {
pqcLivePrecompiles: [],
pqcTestnetPrecompiles: [],
p256: null,
ecrecover: { address: '0x1', name: 'ECDSA secp256k1 (implicit EOA authentication)', confidence: 'certain' },
},
flags: [],
migration: 'Move control to a PQC smart account (AerePQCAccount, Falcon-512 owned) or a hybrid account (AereHybridAuth, ECDSA + Falcon-512). See the migration SDK.',
};
}
/**
* Analyze contract bytecode already in hand (offline path). `code` is a
* 0x-prefixed hex string.
*/
export function scanBytecode(address, codeHex) {
const bytes = hexToBytes(codeHex);
if (bytes.length === 0) return classifyEoa(address);
const analysis = analyzeBytecode(bytes);
return { address, ...analysis };
}
/**
* Live scan: fetch code over RPC, then classify. [MEASURE] path, requires a
* reachable RPC. Falls back to a clear error the CLI can present.
* @returns {Promise<object>} report with a `.live` block
*/
export async function scanLive(address, rpcUrl, { timeoutMs } = {}) {
if (!isValidAddress(address)) throw new Error(`invalid address: ${address}`);
const chainId = await getChainId(rpcUrl, timeoutMs);
const code = await getCode(rpcUrl, address, timeoutMs);
const report = scanBytecode(address, code);
report.live = { rpcUrl, chainId, codeBytes: (code.length - 2) / 2 };
return report;
}