542 lines
57 KiB
Markdown
542 lines
57 KiB
Markdown
# Quantum exposure report
|
|
|
|
A command-line tool that classifies a list of Bitcoin and Ethereum addresses by whether their public key is already readable
|
|
from chain data, in one of three declared modes, and writes a dated report: a JSON, a Markdown for people, and an AERE Proof
|
|
Protocol (AIP-23) `compliance` envelope that binds the JSON, so that anyone can check later which report was issued.
|
|
|
|
It records what was readable on the date of the report. It does not protect, move or recover any coins, it does not change
|
|
what a spend reveals once a quantum computer exists, and it says nothing about the future.
|
|
|
|
```
|
|
node raport.mjs --mod 1 --adrese addresses.txt --iesire out/
|
|
node raport.mjs --mod 2 --adrese addresses.txt --electrum 127.0.0.1:50001 --iesire out/
|
|
node raport.mjs --mod 2 --adrese addresses.txt --esplora http://127.0.0.1:3000 --iesire out/
|
|
node raport.mjs --mod 2 --adrese addresses.txt --bitcoind http://127.0.0.1:8332 --txids ids.txt --iesire out/
|
|
node raport.mjs --mod 2 --adrese addresses.txt --eth-rpc http://127.0.0.1:8545 --eth-blocks 20000000..20000500 --iesire out/
|
|
node raport.mjs --mod 3 --adrese addresses.txt --esplora https://example-provider.invalid --consimtamant-tert "written consent" --iesire out/
|
|
```
|
|
|
|
`addresses.txt` holds one entry per line: a Bitcoin address (base58check, bech32 or bech32m, checked), `script:<scriptPubKey
|
|
hex>`, `p2pk:<public key hex>`, or an Ethereum address (mixed case is checked as EIP-55).
|
|
|
|
Requirements: Node.js 24 and two packages declared in `package.json`, `@noble/hashes` (keccak-256, RIPEMD-160) and
|
|
`@noble/curves` (secp256k1 public-key recovery): run `npm install --ignore-scripts --no-audit --no-fund` in this directory. The
|
|
loader (`noble.mjs`) also accepts the packages from a parent `node_modules`, from a directory named by `AERE_EXPUNERE_NODE_MODULES`
|
|
(the test sets it to this directory's `node_modules` for the copies it runs), or from the AERE anchor verifier's `node_modules`
|
|
when this directory lives in the AERE development tree, and uses a candidate only when it has the exports the tool calls: a
|
|
`@noble/curves` 2.x found first (it has no `ProjectivePoint` and no `CURVE`) is passed over for the next one. Without a usable
|
|
version the tool and the test stop with exit code 2 and name the missing package and what was found; they do not crash inside
|
|
an import. For Bitcoin Core, credentials come from `AERE_BITCOIND_COOKIE` (path of
|
|
the node's cookie file) or `AERE_BITCOIND_AUTH` (`user:password`); no value of either is ever printed.
|
|
|
|
## The three modes
|
|
|
|
| mode | reads | opens connections to | sees spends |
|
|
|---|---|---|---|
|
|
| 1, offline | nothing but the address | nobody | no |
|
|
| 2, your own node or index | your Electrum server, Esplora index, Bitcoin Core or Ethereum JSON-RPC, through one adapter | that one declared target | Electrum and Esplora: yes, as served by them, on the chain they serve (its genesis block, checked against the address's network, and on Bitcoin mainnet its block at a checkpoint height, checked against the checkpoint) and up to the tip they serve (read before the history; both named in every verdict), for the address and for its sibling scripts (below); Bitcoin Core: only the transactions named in `--txids` (it keeps no address index), read once for the whole report, and judged per address, on the chain the node serves (its genesis block and its block at a checkpoint height, read once and judged as for Electrum and Esplora). Since no answer of the node shows that list to be the whole history of an address (an output funded and spent by transactions not given is invisible to it), an address read through Bitcoin Core is `exposed` or `unmeasured`, never `no on-chain evidence of exposure`; the reason names the case: no list, a list none of whose confirmed transactions touches the address (a touch only in the node's mempool is not one, and is named), an output of the address the node no longer holds as unspent and whose spending transaction is not in the list, or a list that the tool cannot check is complete; Ethereum: the blocks of the `--eth-blocks` window |
|
|
| 3, a third-party provider | the same adapters | that provider, only with `--consimtamant-tert "<written consent>"`; the addresses are sent to it; a target that resolves to a private or loopback address is refused | as in mode 2 |
|
|
|
|
Mode 1 classifies by script or address type only. Mode 2 is what a custodian runs against its own infrastructure. Mode 3 exists
|
|
for a requester without a node and is refused without the explicit consent flag; the consent text is recorded in the report.
|
|
|
|
## The two labels, and what each verdict carries
|
|
|
|
Every address receives exactly one of two labels, or the state `unmeasured` with a named reason:
|
|
|
|
- `exposed (on-chain evidence)`: a public key, or the script holding the keys, is readable from chain data the report names.
|
|
- `no on-chain evidence of exposure`: nothing read in this mode shows the key. It says nothing about disclosure off chain,
|
|
about data this mode cannot read, or about the future.
|
|
|
|
Each verdict lists what was seen and what was not seen, in a fixed vocabulary, for example:
|
|
|
|
- `P2PK output: the public key is the script`
|
|
- `P2TR output: the output key (the tweaked public key) is the script`
|
|
- `public key revealed in the scriptSig (HASH160 equals the address hash), in the spend <txid> (input 0, height H)`
|
|
- `P2SH redeem script (HASH160 equals the address hash): 2-of-3 multisig, 3 public keys revealed, in the spend <txid> ...`
|
|
- `the script commits to HASH160 of a key, and 1 public key(s) with that hash are pushed in the same input` (P2PKH-shaped
|
|
redeem or witness scripts, hash-locked contracts)
|
|
- `public key recovered from the signature of transaction <hash> in block H; keccak256 of that key gives this address`
|
|
- `EIP-7702 delegation designator in the account code ...: the chain sets this code only after an authorization signed with
|
|
this account's own key was included`, and, when found in the window, `authorization signed by this account in transaction
|
|
<hash> ...: the authority recovered from the authorization's signature is this address`
|
|
- not seen in mode 1: `spends from this address (mode 1 reads no chain data; a single spend would reveal the key or the script)`
|
|
- in every Electrum or Esplora verdict: `history served up to height H (tip header time T)` and `chain served: Bitcoin mainnet
|
|
(genesis block 000000000019d6...; at height 969696 the block 000...9f0b, the checkpoint this tool holds; the tip header states
|
|
a target within its proof-of-work limit; whether it is the chain with the most work is not verified)`; in every Bitcoin Core
|
|
verdict the same chain line, without the tip; in every Ethereum verdict: `head block N served by the endpoint (block time T)`,
|
|
and the account's nonce and code `at head block N, proven under its state root (eth_getProof)`
|
|
- `the same HASH160 of the key under another script type, P2WPKH bc1q...: public key revealed in the witness ...`, or, beside
|
|
"no on-chain evidence", `sibling scripts of the same HASH160 read through the same target: ...; no spend there reveals the key`
|
|
|
|
Every "revealed" statement is computed by the tool from the bytes the target served, never copied from an index's label:
|
|
|
|
- a public key is a 33-byte (02/03), 65-byte (04) or hybrid 65-byte (06/07, the parity of y in the prefix, accepted by consensus)
|
|
push that decodes as a point on secp256k1, and it counts when its HASH160 equals the address hash (any push of the scriptSig,
|
|
any element of the witness: a legacy scriptSig need not end with the key), or equals a 20-byte hash the revealed script commits
|
|
to; a push whose HASH160 equals the hash but that does not decode as a key is named, and gives `unmeasured`;
|
|
- a redeem or witness script counts when its HASH160 (P2SH) or SHA-256 (P2WSH) equals the hash in the output;
|
|
- inside a revealed script of no standard form, a key counts only when it is a valid point AND the operand of a signature check
|
|
(`OP_CHECKSIG`, `OP_CHECKSIGVERIFY`, `OP_CHECKSIGADD`, or the key run of an `OP_CHECKMULTISIG`); a push that only has the shape
|
|
of a key is reported as such and gives `unmeasured`, not `exposed`;
|
|
- every Bitcoin transaction must hash to its id: Electrum and Bitcoin Core from its raw bytes (or, for a Bitcoin Core node that
|
|
serves no `hex`, re-serialized from its decoded form), Esplora re-serialized from the fields the index serves. The id does not
|
|
cover the witness: a key or a script found there counts by its own hash equality with the address, which no served byte can
|
|
fake;
|
|
- an Ethereum key is recovered from a transaction or authorization signature and must hash to the address, and the transaction
|
|
that carries it (the one sent, or the type-4 transaction that carries the authorization) must hash to the hash the endpoint
|
|
gives, re-derived from its served fields.
|
|
|
|
For Ethereum, the nonce and the code of an account are read only at the head block the verdict names, from an account proof
|
|
(`eth_getProof`) under the state root of that block, and the code must hash to the code hash proven (below, "The head of an
|
|
Ethereum endpoint"); nothing is read at `latest`. A nonce above zero with no transaction or authorization found in the searched
|
|
blocks gives `unmeasured`, with the advice to widen `--eth-blocks`; a window that would read no block (it starts after the head)
|
|
is refused. Every Ethereum verdict names the head block the endpoint served and its time.
|
|
|
|
What gets NO label at all, `exposed` or not, and is `unmeasured` with its reason (README sections below):
|
|
|
|
- a Bitcoin target (Electrum, Esplora, Bitcoin Core) that serves ANOTHER CHAIN than the address's network: its genesis block is
|
|
not one of that network (a `p2pk:` or `script:` line names no network and is read on Bitcoin mainnet only), or the tip header it
|
|
serves (Electrum, Esplora) states a proof-of-work target above the limit of the chain its genesis block names (a signet or
|
|
regtest header served under the mainnet genesis block), or, under the mainnet genesis block, its block at the checkpoint height
|
|
(below) is not the checkpoint, which is what a chain that split from Bitcoin (Bitcoin Cash, Bitcoin SV, eCash) serves: `the
|
|
target serves another chain`; and a target under the mainnet genesis block whose chain ends below the lowest checkpoint, where
|
|
such a chain cannot be told apart;
|
|
- a target that serves blocks AFTER the report date: the header time of its tip, the time of an Ethereum head, or the block time
|
|
of a transaction given to Bitcoin Core is more than 2 hours after the reference instant (below), and, for Bitcoin Core, whose
|
|
scan reads the node's unspent set at the time of the run, a report dated a day that ended more than 2 hours before the run:
|
|
`the target serves blocks after the report date`. A transaction given to Bitcoin Core, on the node's active chain, served
|
|
without its block time, cannot be placed against the date and leaves every address unmeasured too.
|
|
|
|
What never becomes `no on-chain evidence of exposure`, and is `unmeasured` with its reason instead:
|
|
|
|
- an empty, erroneous, truncated or inconsistent answer (a transaction that does not hash to its id, fewer transactions than the
|
|
target counts, an index that counts more spent outputs, or more outputs to the script, than the pages it served carry, a count
|
|
of an Esplora index that is not a count: null, a string, a negative or a missing value, which is never read as zero, a
|
|
transaction in the history of a script that neither pays nor spends it, an identifier that is not one: a transaction id or a
|
|
block hash that is not 64 hex digits, which is quoted as the target's text);
|
|
- anything read through Bitcoin Core that is not `exposed`. In order: without `--txids`, or with a `--txids` list none of whose
|
|
CONFIRMED transactions touches the address (the scan sees only unspent outputs, so a spent output is invisible there; a list
|
|
given for other addresses says nothing about this one, and a transaction the node holds only in its mempool says nothing about
|
|
the address's history on chain); with an incomplete list (an output of the address read from the given transactions that the
|
|
node's scan no longer finds unspent, and that none of them spends, was spent by a transaction not given, where the key may be
|
|
revealed); and otherwise because the tool cannot check that the list is the address's whole history: the label "no on-chain
|
|
evidence" would rest on the requester's list, not on a measurement. Read the address through an index that serves its history
|
|
(Electrum, Esplora) to measure it;
|
|
- a revealing spend that the target holds only in its mempool (public, but not on chain yet), or a spend its index counts in the
|
|
mempool and its pages did not carry; for a P2TR, P2PK or bare-multisig script that already has an output on chain, a pending
|
|
spend does not take that evidence away, and the label stays `exposed`. For Bitcoin Core, "on chain" means a block of the
|
|
node's ACTIVE chain: a transaction it serves with a block hash and `confirmations` 0 (a block off its active chain, which its
|
|
transaction index still names) is treated like one in its mempool, and the reason names it;
|
|
- a P2TR, P2PK or bare-multisig output that the target holds only in its mempool (its key is public there, not yet on chain), or
|
|
that an Esplora index COUNTS in its mempool (`mempool_stats.funded_txo_count`) above the unconfirmed outputs its page carried;
|
|
and an Esplora index that counts more transactions of the script in its mempool (`mempool_stats.tx_count`) than its page
|
|
carried, or that serves no `mempool_stats` counts that are counts (none of these comparisons can then be made), unless the key
|
|
is already on chain (the answer is incomplete, and what it did not serve may show the key);
|
|
- a target BEHIND the chain: the header time of the tip it serves is more than 2 hours before the reference instant (below), or
|
|
its tip could not be read; an Ethereum endpoint whose head time is more than 30 minutes before it, that reports through
|
|
`eth_syncing` that it is syncing, or whose head was not read; an Ethereum account whose state at that head was not proven (no
|
|
`eth_getProof` at the head number, a proof that does not lead to the head block's state root, a code that does not hash to the
|
|
code hash proven); and a sibling script (below) that could not be measured;
|
|
- a spend whose revealed script form this tool does not classify, and a spend SEEN of a hash-type output in which the tool reads
|
|
no key or script: a valid spend reveals the preimage of the hash, so such a spend holds it in a form this tool does not read.
|
|
"Seen" means that the input spends an output paying the address (its funding was read), or that a push or a script in it hashes
|
|
to the address, even when the funding was not served: a segwit spend served without its witness (the transaction id does not
|
|
cover the witness) still carries the redeem script that hashes to a P2SH-P2WPKH address.
|
|
|
|
## The chain and the tip of the target
|
|
|
|
An Electrum or Esplora adapter first reads which CHAIN the target serves: Electrum `server.features` (its `genesis_hash`), Esplora
|
|
`/block-height/0`. The genesis block must be one of the networks of the address: base58check `1...` / `3...` and bech32 `bc1` are
|
|
Bitcoin mainnet; base58check `m...` / `n...` / `2...` are testnet3, testnet4, signet or regtest, bech32 `tb1` the first three, and
|
|
`bcrt1` regtest; a `p2pk:` or `script:` line names no network and is read on mainnet only. The five genesis hashes are in
|
|
`bitcoin.mjs` (`RETELE_BTC`, from Bitcoin Core's chain parameters; the test recomputes each from the fields of its genesis header),
|
|
with each chain's proof-of-work limit. Every Electrum or Esplora verdict names the chain served, as its second evidence line
|
|
(and every Bitcoin Core verdict as its first): `chain served: Bitcoin mainnet (genesis block 000000000019d6...; at height 969696
|
|
the block ..., the checkpoint this tool holds; ...)`.
|
|
|
|
A chain that split from Bitcoin after its genesis block shares that block and the proof-of-work limit: Bitcoin Cash split at
|
|
height 478559, and Bitcoin SV and eCash split later from Bitcoin Cash; their Electrum and Esplora servers are public and answer
|
|
with the mainnet genesis hash, and their tips state mainnet-range targets. So on Bitcoin mainnet the adapter also reads the block
|
|
the target serves at a CHECKPOINT height (Electrum `blockchain.block.header`, whose 80 bytes must be a header; Esplora
|
|
`/block-height/:h`; Bitcoin Core `getblockhash`), and its hash must be the checkpoint's: otherwise the address is `unmeasured`,
|
|
`the target serves another chain: one that shares the genesis block of Bitcoin mainnet and split from it before height H`, and the
|
|
chain line no longer says "Bitcoin mainnet". The checkpoints are in `bitcoin.mjs` (`RETELE_BTC.mainnet.puncte`): blocks 967680 and
|
|
969696, the two pins of the shield's Bitcoin header follower (`btc/antete.mjs`, `PUNCTE_PINATE`), whose hash and 80 header bytes
|
|
were read from two public block explorers of different operators on 2026-10-11 and agreed; that agreement is their whole
|
|
provenance, and the test requires the tool's table to equal those pins and each header to hash to its hash and meet its proof of
|
|
work. The adapter uses the highest checkpoint at or below the end of the target's chain (its tip height; for Bitcoin Core
|
|
`getblockcount`). What this does NOT tell apart: a chain that split from Bitcoin AFTER the checkpoint used (none is known on
|
|
2026-10-12); and a target whose chain ends below the lowest checkpoint (967680) cannot be checked at all, so it is `unmeasured`.
|
|
The test networks hold no checkpoint: a chain that shares one of their genesis blocks (every custom signet shares the default
|
|
signet's) is not told apart from it. None of this shows the chain to be the one with the most work.
|
|
|
|
It then reads the target's tip BEFORE the history: Electrum `blockchain.headers.subscribe` (its height and its 80-byte header);
|
|
Esplora `/blocks/tip/height`, the hash of the block at that height (`/block-height/:h`) and that block's header
|
|
(`/block/:hash/header`), which must hash to that hash. A header counts only when its hash meets the proof of work its own `bits`
|
|
field states (every block header does), and its `bits` must state a target within the proof-of-work limit of the chain the genesis
|
|
block names: a signet or regtest header (easy targets) served under the mainnet genesis block is not a mainnet header, and the
|
|
address is `unmeasured`, `the target serves another chain`. This does not show the header to be on the chain with the most work:
|
|
a target that serves the mainnet genesis block and headers mined at mainnet's minimum difficulty would pass, which this report
|
|
does not verify (Limits). Every transaction confirmed at or below that height is in the history served after it, and every
|
|
verdict says `history served up to height H (tip header time T)`. Each Esplora path is a separate HTTP request: behind a load
|
|
balancer the genesis block, the checkpoint block, the tip and the history may come from different machines, and no answer shows
|
|
it; this is NOT measured, and the test does not exercise it.
|
|
|
|
`no on-chain evidence of exposure` is given only when T is at most **2 hours** before the reference instant: the end of the
|
|
report's date, or the moment of the run when that comes first (a report dated today is judged against the clock of the machine
|
|
that runs it; a wrong clock moves the reference). Otherwise the address is `unmeasured`, `target behind the chain: tip H at T`.
|
|
Why 2 hours: blocks arrive every 10 minutes on average, and under the exponential model of block arrivals a gap of more than two
|
|
hours has a probability of about e^-12 per block (about once in three years; a model, not a measured frequency); a header's time
|
|
is set by its miner and only has to exceed the median of the 11 previous blocks, so the tip of a target that has caught up can
|
|
carry a time up to about an hour old. Two hours keep such a target measurable, and leave a target about 12 or more blocks behind
|
|
unmeasured. A target behind by less than that is not detected; the verdict names H and T so that the reader can see it. A target
|
|
that serves a recent tip and an old history is serving a chain that is not the canonical one, which this report does not verify
|
|
(Limits). An `exposed` verdict does not depend on how far behind the tip is: the evidence it names is on chain whatever came after.
|
|
Bitcoin Core verdicts name no tip: through Bitcoin Core an address is never `no on-chain evidence of exposure` (its verdicts rest on
|
|
the transaction ids the requester gives, each hashed to its id). Bitcoin Core is asked which chain it serves, once per report
|
|
(`getblockhash 0`, `getblockcount`, `getblockhash` at the checkpoint height), and judged by its genesis block and its checkpoint
|
|
block as above; it serves no tip header here, so the proof-of-work limit is not judged for it.
|
|
|
|
## The head of an Ethereum endpoint
|
|
|
|
The Ethereum adapter reads `eth_syncing` and the HEAD block (the block at the number `eth_blockNumber` gave, without its
|
|
transactions) before the account. Every Ethereum verdict names it: `head block N served by the endpoint (block time T)`.
|
|
`no on-chain evidence of exposure` is given only when the endpoint does not report that it is syncing (`eth_syncing` false) and
|
|
T is at most **30 minutes** before the reference instant; otherwise `unmeasured`, `endpoint behind the chain`, with the head or
|
|
the sync status named. Why 30 minutes: a block every 12-second slot, so an endpoint that has caught up serves a head seconds old;
|
|
the margin leaves room for a skewed clock and a run of missed slots, and leaves an endpoint about 150 or more blocks behind
|
|
unmeasured. An endpoint behind by less than that is not detected; the verdict names the head so that the reader can see it. A
|
|
nonce of 0 read at an old head says nothing about the transactions sent after it, which is the reason for the rule.
|
|
|
|
The account is read AT that head and nowhere else: `eth_getProof(address, [], N)` at the head number N, an account proof that is
|
|
walked from the `stateRoot` of the head block just read, every node looked up by its own keccak hash (`ethereum.mjs`
|
|
`contDinDovada`; the walker follows the published one beside the AERE anchor verifier, and the test runs both on the same proofs),
|
|
which gives the nonce and the code hash (or shows the account absent: nonce 0, no code); then `eth_getCode` at N, which must hash
|
|
to that code hash. Behind a load balancer, a machine that does not hold block N answers with an error (`header not found`), and a
|
|
proof of any other state does not lead to that state root: the account is then `unmeasured`, named, never labelled from a nonce
|
|
or a code read at `latest` from another machine; and a state reached after the head (an EIP-7702 designator set later, say)
|
|
cannot be credited to block N. An endpoint that does not serve `eth_getProof` (or no longer keeps the state of block N) leaves the
|
|
account `unmeasured`, named: that is the price of this binding. What the proof binds: the nonce and the code to the state root of
|
|
the block whose number and time the verdict names. What it does NOT bind, and is NOT measured: that block itself to the chain
|
|
Ethereum agreed on. Its number, time and state root are the endpoint's answer, and this tool checks neither the block's hash, nor
|
|
its parent, nor the attestations of the validators (no light client is run here); an endpoint that serves a block of its own
|
|
making, with a state of its own making, is not detected. The blocks of the `--eth-blocks` window are separate requests, each
|
|
checked only through the transactions it carries (each hashed to its served hash, each key recovered).
|
|
|
|
## The date of the report
|
|
|
|
`--data YYYY-MM-DD` is the day the report records (default: the UTC day of the run), and the reference instant is the end of that
|
|
day, or the moment of the run when that comes first. A day after the UTC day of the run is refused (exit 1, nothing written: no
|
|
report and no envelope dated in the future). A day in the past is accepted, and no verdict, `exposed` or not, may rest on what the
|
|
target served after it: the header time of an Electrum or Esplora tip, the time of an Ethereum head and the block time of every
|
|
transaction given to Bitcoin Core must be at most 2 hours after the reference instant (mainnet nodes refuse a header more than 2
|
|
hours ahead of their own clock, so a target that serves the chain passes this for a report dated the day it is run). Bitcoin Core's
|
|
scan reads the node's unspent set at the time of the run, so a Bitcoin Core report dated a day that ended more than 2 hours before
|
|
the run is unmeasured on every address. Otherwise the address is `unmeasured`, `the target serves blocks after the report date`.
|
|
|
|
## The same key under another script type
|
|
|
|
One key stands behind several scripts that the same 20-byte HASH160 determines: P2PKH, P2WPKH and P2SH-P2WPKH (whose redeem script
|
|
is `0x0014 || hash`). A spend from any of them reveals the same key. In modes 2 and 3 the tool reads these SIBLING scripts too:
|
|
for a P2PKH or P2WPKH input the other two forms of its hash (the key itself is not known from a hash, so nothing else is derived).
|
|
A `p2pk:` input gives the key itself, so more is derived from it (12 siblings): the three forms of HASH160 of the key as given; the
|
|
same point in each of its other encodings (compressed 02/03, uncompressed 04, hybrid 06/07, each accepted by consensus in a
|
|
signature check) under P2PK and under the three forms of its own HASH160; and the P2TR output of the key used as an internal key
|
|
with no script tree (BIP-86: Q = P + t*G, t a hash of P; the test checks the derivation on the BIP-86 test vector). Electrum and
|
|
Esplora read each sibling by its script, through the same target (mode 3 therefore sends the siblings to the provider too);
|
|
Bitcoin Core judges each sibling on the given transactions, with no scan of its own (an unspent P2PK or P2TR output of a sibling
|
|
that no given transaction carries is not seen: that can leave the input `unmeasured` where a scan would show it `exposed`, never
|
|
`no on-chain evidence`, which Bitcoin Core never gives). A sibling that shows the key on chain makes the input `exposed`, with the
|
|
sibling and its relation named (`the same HASH160 of the key under another script type, ...`, `the same key in its uncompressed
|
|
encoding, under P2PKH ...`, `a P2TR output with no script tree (BIP-86) whose internal key is this key, ...`). A BIP-86 output
|
|
shows its output key, this key tweaked, not this key itself: the verdict says so in its "not seen" column (whoever recovers the
|
|
private key of the output key controls that output, and the private key of this key follows from it for anyone who also knows this
|
|
key). A sibling that cannot be measured leaves the input `unmeasured`; beside `no on-chain evidence of exposure` the siblings read
|
|
are listed. What cannot be derived from an input is named in its "not seen" column (project document, N8): for a P2PKH or P2WPKH
|
|
input, a P2PK or bare-multisig output holding the key itself, a P2TR output or script, a P2SH or P2WSH script holding the key and
|
|
the key in its other encoding (another HASH160); for a `p2pk:` input, only what depends on something the input does not give: a
|
|
P2TR output whose key commits to a script tree, a P2SH or P2WSH script holding the key, a bare-multisig output holding it (the few
|
|
forms that commit to this key alone, such as a 1-of-1 multisig or a P2WSH of `<key> OP_CHECKSIG`, are not searched either); and, for
|
|
a P2SH, P2WSH or P2TR input, the keys inside it under any other type. Each such verdict also names the other chains that may share
|
|
the key (an EVM chain where the same address is the same account, a Bitcoin fork, a test network) and says which one chain was read.
|
|
|
|
## What a chain cannot show: the declarations
|
|
|
|
The report asks three questions and records the answers as declarations by the requester, never as measurements, and no answer
|
|
changes a label:
|
|
|
|
1. whether an extended public key (xpub / ypub / zpub) of a wallet holding any of the addresses was ever given to a third party
|
|
(a service, a companion application, a co-signer, a backup);
|
|
2. whether any of the keys signed anything off chain: Bitcoin signed messages (BIP-137, BIP-322), PSBTs sent to others,
|
|
Ethereum EIP-191 or EIP-712 signatures (permits, exchange orders, sign-in messages), or a transaction that was broadcast and
|
|
never confirmed (replaced by fee, dropped from mempools): it disclosed the key exactly as a confirmed spend would, and once it
|
|
is gone no chain shows it;
|
|
3. whether the same key, or the same address, signed on another chain: another EVM chain where the address is the same account
|
|
(a layer 2, a sidechain, a test network), a Bitcoin fork that shares the history before its split, a test network, or a chain
|
|
of another kind using the same secp256k1 key. The report read one chain, named in each verdict.
|
|
|
|
`--xpub-partajat da|nu|necunoscut`, `--semnaturi-offchain da|nu|necunoscut` and `--alte-lanturi da|nu|necunoscut` give the
|
|
answers; without them the report says the question was asked and not answered.
|
|
|
|
## Deadlines cited
|
|
|
|
The report cites, for the classical algorithms behind every address (ECDSA and Schnorr on secp256k1), the deadlines of NIST IR
|
|
8547 (initial public draft, document date 2024-11-12: deprecated after 2030, disallowed after 2035) and of the EU coordinated
|
|
implementation roadmap (2025-06-23: inventory by 2026-12-31, high-risk use cases by 2030-12-31, medium-risk by 2035-12-31),
|
|
and, with `--cnsa`, CNSA 2.0 as a secondary-source citation. Each regime is listed with its document, version or status, source
|
|
and the date it was read. The values come from one place, the compliance-report module of the control plane; this tool does not
|
|
keep its own copy.
|
|
|
|
## Output
|
|
|
|
`raport.json` (the report), `raport.md` (the same for people) and `plic-aip23.json`: an AIP-23 `compliance` envelope whose
|
|
`evidenceHash` is the SHA-256 of the canonical JSON of `raport.json` (keys sorted recursively, no spaces), with `subject` (a label
|
|
derived from the address list, or `--subiect`), `policy` (the report format version) and `result` (the summary line). The
|
|
envelope is checked by the published AIP-23 reference verifier (form and integrity levels; the finality level applies once the
|
|
envelope is notarized). The report contains the addresses and nothing about who holds them.
|
|
|
|
Exit codes: 0 report written and every address classified; 2 report written with some addresses unmeasured, or the tool could
|
|
not run (a missing dependency, named); 1 refused (bad input, no consent in mode 3, a private target in mode 3, a data-source flag
|
|
in mode 1, a transaction id given with `--txids` that the node does not serve, whose bytes do not hash to it, or whose block hash
|
|
is not one, an `--eth-blocks` window that starts after the head, a `--data` day after the UTC day of the run, or a report whose own
|
|
text would contain a word the language gate forbids), and then nothing is written. The language gate judges the tool's text; what the requester gave verbatim (the
|
|
`--subiect` label, the consent text, the address lines, the target's host) is recorded as given, and so is what the target served
|
|
(an error body, an error message, a server version string, an identifier or a quantity that is not one, and the WHOLE message of
|
|
a TLS error, which carries the names of the target's certificate), which the report quotes as `[served: ...]`; a message cut to its length limit inside such a quote keeps the quote closed. A value that the tool converts
|
|
(an Ethereum quantity, a signature field) is checked for its form first, so that a conversion error never carries the served text
|
|
into the report, and the delegate of an EIP-7702 authorization is written from the bytes the authority signed. The gate's words
|
|
(listed in `limbaj.mjs`, the one file that names them) are bounded by letters and digits only, so a hyphen or a space before or
|
|
after a word does not shield it, and its compounds are caught written with a hyphen, a space or nothing; the tool's own negations
|
|
("it does not protect") stay clean. Error
|
|
messages mask every long hexadecimal string, except the transaction id a refusal names, which is the requester's own input.
|
|
|
|
## Proof that nothing leaves the machine
|
|
|
|
`paza-retea.mjs` is a connection counter loaded into the report process before the tool (`node --import paza-retea.mjs
|
|
raport.mjs ...`). It journals, and in blocking mode refuses before any packet leaves:
|
|
|
|
- every TCP connection opened through `net.Socket` (net, tls, http, https, http2, fetch, WebSocket), its arguments read the way
|
|
Node.js reads them; when the caller supplies its own `lookup`, the address that lookup returned is journaled too;
|
|
- every connection of `net.Socket` to a path (a named pipe, a Unix socket, an HTTP `socketPath`, or a string given to
|
|
`socket.connect` that is not a port, which Node.js opens as a pipe), judged on the path AS THE SYSTEM OPENS IT, not on the
|
|
string given: on Windows the path is normalized first (`\\.\pipe\..\UNC\host\pipe\x` is opened as `\\.\UNC\host\pipe\x`, over
|
|
SMB), and only the local pipe namespace passes, `\\.\pipe\<name>` or `\\?\pipe\<name>` with a name that holds no backslash.
|
|
Every other form is judged like a host: a UNC name, an NT path such as `\??\UNC\host\...`, a GLOBALROOT device path, a drive or a
|
|
relative path (which may be a network mount). This is a list of what passes, not of what is forbidden;
|
|
- every UDP send, its arguments read the way Node.js reads them (a connected socket sends to its remote address, and an offset or
|
|
a length is not a port; a port may be a numeric string; no address means the loopback), and every multicast membership change
|
|
(`addMembership` and the rest, which make the system send an IGMP or MLD report);
|
|
- every DNS function of `dns`, `dns.promises`, `dns.Resolver` and `dns.promises.Resolver` that may send a query (all but
|
|
`getServers`, the result-order pair, `cancel` and `setLocalAddress`), so that a query function added by a later Node.js is
|
|
judged too (Node 24 has `resolveTlsa`, which a fixed list had missed). Only `lookup` passes, for a declared target name or an IP
|
|
literal (`getaddrinfo` sends nothing for a literal); `resolve*`, `reverse`, `lookupService` and every other query go to a DNS
|
|
server whatever host they name, and are refused. `setServers`, which decides where every later query goes, is journaled and
|
|
refused, on the module, on `dns.promises` and on the base prototype the `Resolver` instances share;
|
|
- every call of `process.binding` (the door to the internal TCP, UDP and DNS handles, which do not go through `net.Socket`), every
|
|
native addon load (`process.dlopen`), every worker thread (`worker_threads.Worker` is replaced by a constructor function, so the
|
|
original is not reachable as its prototype), and every child process: the `child_process` functions, the `ChildProcess` class
|
|
itself (where every asynchronous form ends) and `process.execve`.
|
|
|
|
What it does not see is said here, not measured as zero: in journal mode, the connections made through a handle taken from
|
|
`process.binding` or by a native addon (only the call or the load is journaled), those of a child process started with its own
|
|
environment (the guard reaches child Node.js processes through `NODE_OPTIONS`, so only when they inherit it; the start is
|
|
journaled), those of programs other than Node.js started as children, and those of the program `process.execve` puts in place
|
|
of the process on POSIX (the call is journaled); in both modes any file opened on a path the system resolves over a network (a
|
|
UNC path, a network mount), whatever opens it (`fs`, `import`, `node:sqlite`: none is wrapped), WHERE a declared target name
|
|
resolves (the system's answer, or the caller's own `lookup`, whose answer is journaled for TCP and not judged), `internalBinding`
|
|
(not reachable without `--expose-internals`), `node:quic` where a build offers it (the Node.js 24.14 measured here has no such
|
|
module, with or without `--experimental-quic`), code written on purpose to reach the original functions by some other way than
|
|
the ones named above (the guard measures the ordinary calls of the tool and of its libraries; it is not a sandbox), and anything
|
|
outside the Node.js process. In blocking mode each of those starts (and every multicast membership change and `setServers`) is
|
|
refused, so none of them runs. Workers are started with the guard preloaded
|
|
(`--require` in their `execArgv`), so in journal mode their connections are in the journal. The tool itself uses none of these
|
|
paths: its sources import no child_process, worker_threads or native module and call no process.binding or lookupService, which
|
|
the test checks.
|
|
|
|
The test (`proba-expunere.mjs`) runs every mode under it: mode 1 shows zero connections and zero DNS queries; mode 2 shows exactly
|
|
as many connections as the mock target accepted, all to the declared host and port. Its negative control plants, in a copy of the
|
|
tool, one exemplar of each path above and requires, in blocking mode, the journal to name each and the guard to refuse each: the
|
|
network paths toward a documentation address (198.51.100.9) or names under `.invalid`, `lookupService` on 127.0.0.1 (a literal is
|
|
a real query there), the named pipe toward 127.0.0.1 as its server, and the paths that carry no address (`process.binding`,
|
|
`process.dlopen`, a worker, the worker taken by reflection, which must not start, a child process through a function and through
|
|
the class, `process.execve`). Three more controls count what ARRIVES at a listener of the test, and each has inverse plantings
|
|
in a copy of the guard itself: the pipe forms that name a server through `..`, through the NT prefix `\??\`, through
|
|
`GLOBALROOT\Device\Mup` or through a string given to `socket.connect` reach a pipe the test listens on (over SMB on loopback)
|
|
when let through, and in blocking mode only the local form arrives (the guard judging the raw string, or reading the string as a
|
|
port with `localhost` declared, lets them arrive); the DNS queries of mode 2's configuration (a reverse, a TXT, a TLSA and an A
|
|
query naming the declared literal or name, and every `setServers`) reach nothing, with the process's DNS servers moved, before
|
|
the guard loads, to a UDP listener of the test on 127.0.0.2, so that nothing leaves the machine even if the guard let them
|
|
through (the old rule for a declared literal, and a fixed list of function names, each let datagrams arrive); and the UDP sends
|
|
to the declared target, in the three argument forms of `send` and through `sendto`, arrive while a send to another port and a multicast membership on the
|
|
loopback interface are refused (the old reading of the arguments, and an unwrapped membership, turn it red). In journal mode,
|
|
where a planted call really runs, it plants only local ones (a worker's and a child's connection to 127.0.0.1, a connected UDP
|
|
socket, a connection with its own lookup) and requires each in the journal. The tool run without the guard produces no journal,
|
|
and the test treats that as unmeasured, not as zero; the planted copy is never run without the guard, since its paths would send
|
|
real packets. The pipe control needs the SMB client of Windows (loopback only) and is not measured on other systems.
|
|
|
|
## Test
|
|
|
|
```
|
|
node proba-expunere.mjs
|
|
```
|
|
|
|
Codec checks with real public vectors (BIP-173/350 test vectors, the EIP-155 example, every mainnet transaction in the fixtures
|
|
re-serialized byte for byte and hashed to its id, every transaction of a recorded Ethereum block with its sender key recovered
|
|
and its hash re-derived, the EIP-7702 authorization of that block with its authority recovered, transactions of types 0x1 and
|
|
0x3 signed with a test key and recovered); mode 1 and mode 2 through four mock targets (Electrum, Esplora, Bitcoin Core, Ethereum
|
|
JSON-RPC) that serve responses recorded from a public index on the date written in `fixturi/*.json`; and negative controls: a
|
|
planted foreign provider on each network path is caught, an empty or error answer and a mute target give `unmeasured`, Bitcoin
|
|
Core without `--txids`, with only the funding transactions of a spent address, with a list that touches only one of the
|
|
addresses, with a list that touches an address only through a transaction in the node's mempool, or with the funding of an
|
|
output still unspent, gives `unmeasured` (never "no on-chain evidence") with the reason of each case, a revealing spend that
|
|
Bitcoin Core names in a block off its active chain gives `unmeasured` (`exposed` once on the active chain), a transaction id the node does not
|
|
serve and a decoded transaction with one value changed are refused (the decoded form is re-serialized and must hash to its id),
|
|
an Esplora transaction whose id or one value was changed gives `unmeasured`, a planted spend on a synthetic address moves the
|
|
label to `exposed` (also through a P2PKH-shaped redeem script and a witness script, through a second Esplora page, through a
|
|
hybrid key and a scriptSig that does not end with the key), a spend seen with no preimage the tool can read gives `unmeasured`
|
|
(also a P2SH-P2WPKH spend served without its witness and without its funding, seen through its redeem script), a
|
|
spend seen only in the mempool gives `unmeasured` while a P2TR output already on chain stays `exposed` beside a pending
|
|
script-path spend, a P2TR output only in the mempool gives `unmeasured`, a replaced spend is named among the declarations, a
|
|
33-byte push in a non-standard witness script that is not the operand of a signature check gives `unmeasured` (the same key under
|
|
`OP_CHECKSIG` gives `exposed`), an EIP-7702 designator gives `exposed`, an authorization in a type-4 transaction whose hash was
|
|
changed is not used as evidence, an `--eth-blocks` window after the head is refused, a forbidden label planted in a copy is
|
|
refused by the language gate while a `--subiect` or an error body served by the target holding such a word is recorded as given,
|
|
and so is, quoted, such a word served in place of an identifier (an Electrum `tx_hash`, an Esplora `txid`, a `scantxoutset`
|
|
output, an Ethereum transaction hash), of a quantity (`eth_chainId`, a signature field) or after the 20 bytes of an EIP-7702
|
|
delegate, and inside a served message cut at its length limit (a Bitcoin Core block hash that is not one refuses the answer
|
|
instead), mode 3 without consent and mode 3 toward a private target are refused with nothing sent, a report or envelope changed after
|
|
signing is refused, a mock started detached by a parent that exits stops by itself, and a `@noble/curves` 2.x found first is
|
|
passed over (exit 0 with 1.x beside it, exit 2 named without); a target whose tip is the real header of block 969686
|
|
(2026-10-03) gives `unmeasured` ("target behind the chain") where the recorded tip gives `no on-chain evidence`, and a tip header
|
|
changed by one byte, or one that does not hash to the block hash the index gives, is not a tip; a key revealed only at a sibling
|
|
script (a P2WPKH spend, for its P2PKH address and for the `p2pk:` line of the key) gives `exposed` with the sibling named, through
|
|
Electrum and Esplora, and every `no on-chain evidence` names the siblings read, the N8 line and the other chains; the third
|
|
question is asked; a TLS listener of the test whose certificate names a forbidden word gives a written report (`unmeasured`, the
|
|
message quoted), not a refusal; an Esplora index that counts a mempool spend its page does not carry, beside another mempool
|
|
transaction of the address that the page does carry, gives `unmeasured`. Since round 7: the five genesis hashes are recomputed
|
|
from their headers and must equal the tool's table, and the BIP-86 derivation must give the BIP-86 test vector; a target serving
|
|
the regtest genesis block and a fresh regtest tip gives `unmeasured` ("serves another chain") for a mainnet address and measures a
|
|
`bcrt1` address; a signet tip (mined once, see the test) under the mainnet genesis block gives `unmeasured` ("above the limit of
|
|
Bitcoin mainnet") for a P2PKH address and a `p2pk:` line, while under the signet genesis block a `tb1` address is measured and the
|
|
`p2pk:` line is `unmeasured` ("mainnet only"); every verdict on the fixtures names the chain; an Ethereum endpoint whose head is
|
|
block 18,000,000 (2023-09-07) or that reports `eth_syncing` gives `unmeasured` ("endpoint behind the chain") where the recorded head
|
|
gives `no on-chain evidence` naming the head; `--data 2030-01-01` is refused in modes 1 and 2, and `--data 2012-01-01` gives
|
|
`unmeasured` ("serves blocks after the report date") on every address through Electrum, Esplora, Ethereum and Bitcoin Core with
|
|
and without `--txids`; through Bitcoin Core, a revealing spend in a block timed 400 days ahead, or served without its block time,
|
|
gives `unmeasured` (`exposed` with a past block time); a `p2pk:` line whose key is shown only in its other encoding (a spent P2PKH
|
|
of the uncompressed form, a P2PK output of the compressed form) or by its BIP-86 output gives `exposed` with the sibling named,
|
|
through Electrum and Esplora, and one with no history gives `no on-chain evidence` with its 12 siblings listed and an N8 line that
|
|
names only what cannot be derived; an Esplora index that counts a mempool output of a P2TR with no output on chain, or a mempool
|
|
transaction of a P2PKH, that its page does not carry gives `unmeasured`. Since round 8: the tool's checkpoints equal the pins of
|
|
`btc/antete.mjs` and their headers hash to their hashes, and the checkpoint chosen is the highest at or below the tip; the trie
|
|
builder of the test gives the known roots of the Ethereum trie test vectors (the empty trie, "dogs", "puppy"), and the tool's
|
|
proof walker agrees with the published one on every proof of the fixture and on an absence; an Ethereum mock that answers as a load
|
|
balancer with a machine behind (`header not found` at the head, nonce 0 at `latest`) gives `unmeasured` for an account that the
|
|
old reading labelled "no on-chain evidence", a state after the head at `latest` (an EIP-7702 designator) does not label the account
|
|
at the head, and a code that does not hash to the proven code hash, a proof of another state and an endpoint without `eth_getProof`
|
|
give `unmeasured`, while the real designator still gives `exposed`; a target of a chain that split from Bitcoin (the mainnet genesis
|
|
block, a real mainnet tip, another block at the checkpoint height) gives `unmeasured` ("serves another chain: ... split from it
|
|
before height 969696") through Electrum, Esplora and Bitcoin Core, and a chain ending below the lowest checkpoint gives `unmeasured`;
|
|
Bitcoin Core on regtest gives `unmeasured` for a `p2pk:` line it would otherwise label `exposed` from its scan; an Esplora count that
|
|
is null, a missing or negative `mempool_stats`, an index that counts more outputs than its pages carry, and a transaction in a
|
|
script's history that neither pays nor spends it (Esplora and Electrum) each give `unmeasured`. For each defect the test exists to catch (an empty answer
|
|
labelled "no on-chain evidence", Bitcoin Core without `--txids`, with an incomplete list, with a list that does not touch the
|
|
address, that touches it only in the mempool, or that cannot be shown complete, labelled "no on-chain evidence", a pending spend
|
|
that removes the evidence of a P2TR output, a spend seen labelled "no on-chain evidence" (also one seen only through its hash), a
|
|
P2TR output only in the mempool labelled "no output exists yet", an Esplora or type-4 transaction cited by an id it does not hash
|
|
to, a served error body or identifier refused by the language gate, a guard that judges a pipe on its raw string, that lets a
|
|
declared literal be queried, that wraps a fixed list of DNS names, that reads a datagram's offset as its port, a mock that
|
|
outlives its parent, a loader that crashes on the wrong `@noble/curves`; since round 6, a tip left unjudged, sibling scripts not read, a TLS message
|
|
left unquoted, the mempool rule that looked only for an empty page; since round 7, a genesis block not compared with the address's
|
|
network, a tip header's proof-of-work limit not judged, an Ethereum head time or sync status not judged, a report date not judged
|
|
or a future one not refused, a Bitcoin Core block time ignored or missing, the other encodings and the BIP-86 output of a `p2pk:`
|
|
key not derived, the mempool output and transaction counts not compared; since round 8, an Ethereum account read at `latest`, its
|
|
proven values replaced by the fields served beside the proof, its code not hashed to the proven code hash, a checkpoint not
|
|
compared, a chain below the lowest checkpoint let through, Bitcoin Core's chain not judged, an Esplora count read as Number(x), an
|
|
unread `mempool_stats` ignored, the outputs counted on chain not compared, a transaction that does not touch the script accepted),
|
|
the test plants the defect in a copy of the tool (or of
|
|
the guard) and requires its own check to turn red on it. Where one rule backs up another (Bitcoin Core never gives "no on-chain
|
|
evidence"), the planting of an earlier rule removes the backstop too, so that each rule is shown to hold the label by itself.
|
|
Every check has three states (green, red, broken); a control that cannot plant is a failure; an exception inside the test is a
|
|
failure (exit 1), never "unmeasured". The copies are siblings of this directory (`.expunere-planta-*`, ignored by git), and the
|
|
test's working directory is `expunere-proba-<pid>-*` in the system's temporary directory; a run that is killed leaves both, and
|
|
the next run deletes those whose process (the pid in the name) is gone, never those of a run still alive. Working directories of
|
|
the form used before 2026-10-12 (`expunere-proba-*` without a pid) cannot be judged: the run names them and leaves them. A pid
|
|
reused by another process keeps its orphan until that process ends. Not measured by the test: mode 3
|
|
against a real provider, and the adapters against real servers (the Bitcoin Core responses in the fixtures are shaped after the
|
|
RPC documentation, not recorded from a node). The sibling scripts of the recorded vectors were not recorded: the mocks answer a
|
|
script they do not hold as an index answers a script never used (an empty history), so the test's `no on-chain evidence` on the
|
|
never-spent P2PKH vector rests on the recorded history of the address itself and on empty, unrecorded answers for its siblings.
|
|
The tip was not recorded with the fixtures either: the mocks serve the real header of block 971000 (2026-10-11T22:53:11Z), taken
|
|
from the header chain the C6 Bitcoin P2P follower validated that evening (provenance in each fixture's `_sursa.nota`), and the
|
|
test dates its reports 2026-10-11, so that the reference instant (the end of that day) is fixed and the tip is within its margin.
|
|
Nor were the genesis answers (`server.features`, `/block-height/0`: the mainnet genesis hash, a constant of the chain that the test
|
|
recomputes) or the Ethereum head and `eth_syncing` (`false`, and for the head block only its number and the EARLIEST time it can
|
|
carry, derived from the recorded block 517 blocks before it; provenance in `_sursa.nota`). Reports through Bitcoin Core are dated
|
|
the day of the run, since its scan reads the node at the time of the run. The Esplora load-balancer case above is not measured.
|
|
Since round 8 the fixtures also answer the checkpoint blocks (Electrum `blockchain.block.header`, Esplora `/block-height/:h`,
|
|
Bitcoin Core `getblockhash`) and the chain of the Bitcoin Core node (`getblockhash 0`, `getblockcount` 971000): none was recorded;
|
|
the checkpoint answers are the pins of `btc/antete.mjs`. The fork of the test serves, at the checkpoint height, the real header of
|
|
another mainnet block (969686), not a header of Bitcoin Cash: no such header can be produced offline, and what the guard compares
|
|
is the hash at that height. The Ethereum STATE of the fixtures is SYNTHETIC: a Merkle-Patricia trie of the four recorded accounts
|
|
(balance 0, empty storage), built from the code and the transaction count recorded at `latest`, whose root is given as the state
|
|
root of the head block (which was not recorded either); the test checks the builder against the Ethereum trie test vectors and
|
|
the walker against the published one, so a real `eth_getProof` answer of a public endpoint is NOT measured here.
|
|
|
|
The fixtures keep every path and field the adapters read on the recorded answers; the paths no adapter requests (Esplora
|
|
`/tx/:id`, `/tx/:id/hex`, `/utxo`) and, in the Esplora transaction pages, the fields the adapter never reads (`*_asm`,
|
|
`scriptpubkey_type`, `scriptpubkey_address`) were removed to keep them small, as written in each file's `_sursa.nota`. The Bitcoin
|
|
Core fixture keeps the node's verbose form with `hex` for every transaction (what the adapter parses and hashes to the id), and
|
|
the decoded `vin` / `vout`, which the adapter reads only when a node serves no `hex`, for the transactions of the three roles on
|
|
which the test exercises that path; its `confirmations` are derived from the recorded heights (the adapter does not read them).
|
|
|
|
The real vectors (`fixturi/vectori.txt`, provenance in `fixturi/alese.json`) are historical or ownerless addresses where a
|
|
never-spent address was needed (the block-1 coinbase key, the P2PKH form of the block-11 coinbase key, a provably unspendable
|
|
and never-funded P2TR address, the BIP-350 example address whose output key is the generator point, the addresses of the
|
|
private keys 3 and 7, the burn address 0x...dEaD), and otherwise addresses with no remaining balance on the recording date.
|
|
|
|
Reviewed on 2026-10-14 (round 9, the hostile review of the round-8 form as left on disk; the round-8 agent was stopped by the
|
|
account's weekly limit before its report): `node proba-expunere.mjs` exit 0, 164 green, 0 red, 0 broken, 1 unmeasured (mode 3
|
|
against a real provider, by design), 123 s; the round-7 reviewer's attack harness replayed against this code: R1 (an Ethereum
|
|
balancer with one machine behind) not reproduced (0 of 40 "no on-chain evidence" with a random balancer, `unmeasured` on each
|
|
route), R3, R4, R5 (Esplora counts) not reproduced, R8 (a key spent before the split) `exposed` on the fork as it must be; R8b
|
|
still prints "no on-chain evidence" in THAT harness only because its mock answers `/block-height/969696` and
|
|
`blockchain.block.header(969696)` with the tool's own checkpoint block (recorded in the fixtures): it models an index that serves
|
|
Bitcoin's headers and checkpoint with a foreign history, which is the lying index named under Limits (the history is not checked
|
|
against the headers with Merkle proofs), not an honest fork, whose block at that height is its own (case m.2, `unmeasured`) or whose
|
|
chain ends below 967680 (m.3, `unmeasured`).
|
|
|
|
## Outside the AERE development tree
|
|
|
|
The tool and its test look for what they need in two layouts: the AERE development tree (`tools/aere-quantum-shield/expunere/`
|
|
beside `cloud-gateway/` and `verificator-falcon/`) and the public copy (`exposure-report/` beside `readiness/`, `control-plane/`
|
|
and `proof-kinds/` in the `aere-quantum` repository). Each file is found by its place, or named by an environment variable:
|
|
|
|
| file | what it is | development tree | public copy | variable |
|
|
|---|---|---|---|---|
|
|
| `adrese-private.mjs` | the private-address guard of mode 3 (required) | `cloud-gateway/` | `readiness/` | `AERE_EXPUNERE_ADRESE_PRIVATE` |
|
|
| `raport-conformitate.mjs` | the compliance-report module: deadlines, canonical hashing (required) | `cloud-gateway/control-plane/` | `control-plane/` | `AERE_EXPUNERE_TERMENE` |
|
|
| `proof-kinds.mjs` | the AIP-23 envelope builder (required) | `tools/proof-kinds/` | `proof-kinds/` | `AERE_EXPUNERE_PROOF_KINDS` |
|
|
| `verify.mjs` | the AIP-23 reference verifier (the test compares with it) | `tools/aere-proof-protocol/` | not in the copy | `AERE_PROOF_PROTOCOL_VERIFY` |
|
|
| `verify-proof.mjs`, `mpt.mjs` | the anchor verifier's RLP encoder and account-proof walker (the test compares with them) | `verificator-falcon/` | not in the copy | `AERE_VERIFY_PROOF` (`mpt.mjs` beside it) |
|
|
| `antete.mjs` | the shield's Bitcoin header pins (the test compares the checkpoints with them) | `tools/aere-quantum-shield/btc/` | not in the copy | `AERE_EXPUNERE_PINI` |
|
|
| `node_modules/` | the two npm packages, for a copy of the tool that has none (the test's copies) | the anchor verifier's | this directory's, after `npm install` | `AERE_EXPUNERE_NODE_MODULES` |
|
|
|
|
The two npm packages are resolved as described at the top (`npm install --ignore-scripts --no-audit --no-fund` in this directory).
|
|
In a copy without the three "compared with" neighbours the test still runs; the rows that need them (the compliance envelopes
|
|
judged by the reference verifier, the RLP encoder, the MPT walker, the checkpoint pins) and the scan of this directory for names
|
|
from the AERE host inventory are reported as `NEMASURAT` with the reason, not as passed; the exit code stays 0, as it does for every
|
|
`NEMASURAT` row (it is 1 only when a row is red or broken). The git-ignore row is `NEMASURAT` outside a git tree. Measured on
|
|
2026-10-14 in the public copy after `npm install`: 153 rows passed, 0 red, 0 broken, 12 `NEMASURAT` (the ten rows above, the
|
|
scan and the git-ignore row); in the AERE development tree: 164 passed, 1 `NEMASURAT` (mode 3 against a real provider). Nothing in the public copy reads anything from the AERE development tree.
|
|
|
|
## Files
|
|
|
|
`raport.mjs` (the command line), `clasifica.mjs` (the classification and its vocabulary), `limbaj.mjs` (the two labels and the
|
|
language gate), `bitcoin.mjs` (addresses, scripts, transactions, evidence from inputs, block headers, the networks and the
|
|
mainnet checkpoints), `ethereum.mjs` (EIP-55, RLP, signing hashes, key recovery, EIP-7702 authorizations, the account-proof walker
|
|
and, for the test, a trie builder), `adaptoare.mjs` (the four adapters), `noble.mjs` (the dependency loader),
|
|
`paza-retea.mjs` (the connection counter), `machete.mjs` (mock targets for the test), `fixturi/` (recorded responses and the
|
|
real vectors), `proba-expunere.mjs` (the test), `package.json`.
|