OpenChainGraph · Explainer

Art 780 Solana PDA Bump and ATA Audit

Paste a claimed program-derived-address tuple and the node recomputes what the Solana runtime rules actually yield for it: the address for the claimed bump, whether that hash can even be a PDA, which bump is canonical, and whether the same seeds hide a second valid address. With a wallet, mint and token program pasted, it derives the associated token account under the declared program and under the classic Token program side by side, so the classic-program derivation of a Token-2022 mint shows up as two different addresses. Every number on this page comes from the pinned Solana sources and recomputes offline in your browser or via the MCP worker.

Presenter mode shows one step per screen. Arrow keys move, A toggles autoplay, Esc exits.
1
Step 1

The derivation is a fixed byte recipe

A program-derived address is nothing more than SHA-256 over the seeds, the bump byte, the program id and the marker string ProgramDerivedAddress.

seeds, in order bump byte program id "ProgramDerivedAddress" SHA-256 32 bytes, base58off-curve, or not a PDA

Pinned at solana-labs/solana commit 7700cb3128c1f19820de67b81aa45d18f73d2ac0, sdk/program/src/pubkey.rs, create_program_address L585-616: the client function hashes every seed in order, then the program id, then the 21 marker bytes, and refuses the result when it decompresses to an Ed25519 curve point. The successor SDK (anza-xyz/solana-sdk commit 021fd2f1864ab194b53498bb03c21ad1dc124b8d, address/src/derive.rs) keeps the identical recipe. The first fixture anchors this node on addresses the pinned test suite itself publishes: seeds [empty] with bump 1 under the upgradeable loader program yield BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe, and the kernel reproduces that byte for byte.

Who asks at this stepMCP
Run the AINumbers MCP tool `audit_solana_pda_ata` with program_id "BPFLoaderUpgradeab1e11111111111111111111111", seeds [{"data":"","encoding":"utf8"}], bump 1 and claimed_address "BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe": the published golden address should come back as derived_hash_base58 with claimed_matches true.
2
Step 2

The canonical bump is the first hit from 255 down

find_program_address tries candidate bumps 255, 254, 253 and so on down to 1, and the first hash that lands off the curve wins.

bump 255254253...down to 1 on-curveon-curveoff-curve canonical bump 253 bump 0 is never tried:the pinned loop runs 255candidates, 255 down to 1

That search order is pinned twice: try_find_program_address in the archived solana-program source starts at 255 and runs exactly 255 iterations, and the successor SDK precomputes the same 255-entry bump table. A claimed bump of 0 can still recompute to a matching address (the pinned test suite publishes one: the sun-sign seed at bump 0 yields 13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19), but it is never canonical. The staged gloss that said the scan runs 255 to 0 is corrected here against the primary text; the kernel states which rule it implements in every output note.

Who asks at this stepMCP
Same tool, seeds [{"data":"","encoding":"utf8"}] with bump 253: claimed_bump_is_canonical comes back true, and canonical_address reads DNKLRoKoM7XxX2iW1PTnqo6iP6CPpVDBgeN9hrpu2R2R, the first off-curve hit below the two on-curve candidates 255 and 254.
3
Step 3

The same seeds can hold two valid addresses

A non-canonical bump that also lands off-curve gives the same seeds a second, different, perfectly valid PDA. That is the substitution class.

seeds ["vault"] bump 254, canonical bump 252, non-canonical HbSEsJZ7N5uN1mEBaVuFVMXDARHcq4e4AmPoWDQbgrzq5mKEiyoA669YYj7QRCfcBdZAnX2r38ZnXKpmk3rFNuFv two off-curve hashes, two real addresses

Fixture F5 pins this pair with real numbers: under the upgradeable loader program, seeds ["vault"] at bump 254 yield HbSEsJZ7N5uN1mEBaVuFVMXDARHcq4e4AmPoWDQbgrzq and at bump 252 yield 5mKEiyoA669YYj7QRCfcBdZAnX2r38ZnXKpmk3rFNuFv. Both decompress off the curve, so both are valid PDAs. A tool that only derives with a stored bump stays silent about the other one; this node reports claimed_bump_is_canonical false and keeps both addresses visible as facts. No wording about attackers or intent: the booleans are the finding.

Who asks at this stepMCP
Run the tool twice with seeds [{"data":"vault","encoding":"utf8"}], once with bump 254 and once with bump 252, claimed_address set to the matching address each time: both runs return claimed_matches true, only the first returns claimed_bump_is_canonical true.
4
Step 4

An on-curve hash is never a PDA

When the 32 hash bytes decompress to an Ed25519 curve point, create_program_address refuses them outright. The audit reports that as the on_curve fact.

SHA-256 output curve point: refused off-curve: valid PDA seeds ["oc0"], bump 255:36ETbDqxX3nXTJSj4MNThicebuuRLsRs58oGudAke7eiis on-curve; the canonicalscan finds bump 254 instead

Fixture F6 is a real case found by search: for seeds ["oc0"] at bump 255 the hash itself is a curve point, so no program can ever own that address as a PDA. The output says on_curve true, create_program_address_verdict on_curve, and still shows the canonical bump 254 with its own address, so a reader sees both facts at once: the claimed tuple recomputes to the claimed string, and that string is unusable as a PDA. The off-curve test is the vendored noble Ed25519 point decompression, the same primitive the estate already uses for signature verification nodes.

Who asks at this stepMCP
Run the tool with seeds [{"data":"oc0","encoding":"utf8"}], bump 255, claimed_address "36ETbDqxX3nXTJSj4MNThicebuuRLsRs58oGudAke7ei": claimed_matches true, on_curve true, canonical_bump 254, and the flags CLAIMED_BUMP_ON_CURVE and NON_CANONICAL_BUMP_CLAIMED together.
5
Step 5

Token-2022 mints need the program id in the seeds

An associated token account is a PDA with seeds [wallet, token program id, mint] under the ATA program. Put the classic Token program in those seeds for a Token-2022 mint and you derive a different account.

wallet mint (Token-2022) seeds [wallet, TokenzQdBNb..., mint]ATA GdjpegrtGwU3pgtzPivYVViSA8rmGL248qBVKzsrU3DD seeds [wallet, TokenkegQfe..., mint]ATA FGETo8T8wMcN2wCjav8VK6eh3dLk63evNDPxzLSJra8B token_program_mismatch: true

The pinned ATA source (solana-program/associated-token-account at 4004274dfb861e09570af873b46cb0b0919e8df0, interface/src/address.rs) states the seed order and, in its own deprecation note, that the classic-only helper "assumes the SPL Token program, which does not work for Token-2022 mints". Free SDK helpers still ship that assumption. Paste wallet, mint and the mint's real token program and the node returns both derivations with their bumps; the mismatch boolean is true exactly when the mint is declared under Token-2022 (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb, pinned in spl-token-2022-interface 3.1.2) and the two addresses differ. Facts only: both addresses are stated, neither is called wrong.

Who asks at this stepMCP
Run the tool with wallet, mint and token_program_id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb: the ata_derivation block returns both addresses (Gdjpegrt... under the declared program, FGETo8T8... under the classic one), both at canonical bump 254, with token_program_mismatch true.
6
Step 6

Manifest & provenance

One input surface, one output contract, one kernel digest, and the whole thing runs offline.

Kernel: chaingraph/kernels/art-780-solana-pda-ata-audit.kernel.mjs: byte concatenation, vendored SHA-256, vendored Ed25519 point decompression and base58 over pasted values; a fixed 255-iteration bump scan whose bound never comes from the inputs; no network, no storage, no RPC. Provenance: solana-labs/solana at commit 7700cb3128c1f19820de67b81aa45d18f73d2ac0 (sdk/program/src/pubkey.rs, create_program_address and try_find_program_address, with the published test vectors as golden fixtures), cross-checked against anza-xyz/solana-sdk commit 021fd2f1864ab194b53498bb03c21ad1dc124b8d (address/src/derive.rs); the ATA program source at solana-program/associated-token-account commit 4004274dfb861e09570af873b46cb0b0919e8df0; the Token-2022 program id pinned in spl-token-2022-interface 3.1.2. Limits follow the primary text: at most 16 seeds counting the bump, each seed at most 32 bytes, reported as facts rather than silently dropped. Prove status: deferred for this new node, picked up by the next proving batch; the property floor already runs an independent reimplementation (a separate SHA-256 and a separately written curve test) against every fixture.

Who asks at this stepMCP
Run the AINumbers MCP tool `audit_solana_pda_ata`. Task: audit a claimed program-derived-address tuple (program id, seeds, bump, claimed address) for canonical-bump correctness and address substitution, and optionally derive the associated token account under a declared token program side by side with the classic Token program for Token-2022 mints.
🔒 All inputs are processed locally in your browser. No data is transmitted. Do not enter real personal data — use synthetic or anonymised inputs only.

Ask your agent

Copy this paragraph into Claude, OpenClaw, or any MCP-aware agent to run this exact tool, with this sample, and verify the artifact.

Run the AINumbers MCP tool `audit_solana_pda_ata`. Task: Audit a claimed Solana program-derived-address tuple (program id, seeds, bump, claimed address): recomputed address for the claimed bump, on-curve fact, canonical bump and address over the 255-to-1 scan, claimed-matches and bump-canonicality booleans, seed limit facts, and optional side-by-side associated-token-account derivation under a declared token program versus the classic Token program (the Token-2022 wrong-derivation class).
Call it with arguments: {"policy_parameters":{"program_id":"BPFLoaderUpgradeab1e11111111111111111111111","seeds":[{"data":"","encoding":"utf8"}],"bump":1,"claimed_address":"BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"}}
Verify before trusting: call `verify_execution_hash` on mcp.ainumbers.co (https://mcp.ainumbers.co/mcp) with the parameter `claimed_hash` set to the returned `execution_hash`, passing the full artifact the run returned (the object containing `policy_parameters` + `output_payload` + `execution_hash`; equivalently `policy_parameters` + `output_payload` with `claimed_hash`), not the bare hash string.
Return the ledger link https://ledger.ainumbers.co/ so a human can re-verify without contacting us.
PII rule: All inputs are processed locally in your browser. No data is transmitted. Do not enter real personal data — use synthetic or anonymised inputs only.
Open the tool with the sample prefilled: https://ainumbers.co/chaingraph/art-780-solana-pda-ata-audit.html#p=v1.H4sIAAAAAAAA_wGuAFH_eyJwcm9ncmFtX2lkIjoiQlBGTG9hZGVyVXBncmFkZWFiMWUxMTExMTExMTExMTExMTExMTExMTExMSIsInNlZWRzIjpbeyJkYXRhIjoiIiwiZW5jb2RpbmciOiJ1dGY4In1dLCJidW1wIjoxLCJjbGFpbWVkX2FkZHJlc3MiOiJCd3FyZ2haQTJodEFjcXE4ZHpQMVdEQWhUWFlUWVdqN0NIeEY1ajdUREJBZSJ9yJtnYK4AAAA