feat(rpc): add zks_getAccountPreimage#1161
Draft
antoniolocascio-bot wants to merge 1 commit intomatter-labs:mainfrom
Draft
feat(rpc): add zks_getAccountPreimage#1161antoniolocascio-bot wants to merge 1 commit intomatter-labs:mainfrom
antoniolocascio-bot wants to merge 1 commit intomatter-labs:mainfrom
Conversation
Exposes the 124-byte `AccountProperties::encoding()` preimage for a given account at the end of a specific L1 batch, under the existing `zks` JSON-RPC namespace. ## Motivation Selective-disclosure tooling that runs over ZKsync OS state (and specifically anything that wants to prove claims about individual `AccountProperties` fields — balance, nonce, observable bytecode hash, versioning data, etc. — inside a zk circuit) needs the full 124-byte encoded preimage of the `AccountProperties` struct. This is because the state tree stores only `blake2s(AccountProperties::encoding())` at the account-properties slot; the Merkle proof returned by `zks_getProof` covers that hash, but not the preimage it commits to. To verify any single field in-circuit against the Merkle-proof- verified tree value, the prover has to feed the exact encoded bytes through blake2s and compare. Partial reconstruction from the existing public surface (`eth_getBalance` / `eth_getCode` / `eth_getTransactionCount`) is not sufficient: `versioning_data`, `bytecode_hash`, and `artifacts_len` are internal fields of `AccountProperties` that are not otherwise exposed over the JSON-RPC surface, and the resulting bytes would not blake2s-hash to the tree value. ## Implementation Thin wrapper around the existing `storage.state_view_at(last_block_of_batch).get_account(address)` path that `eth_getBalance`, `eth_getCode`, etc. already use internally. The new method simply returns `Bytes::copy_from_slice(&props.encoding())` instead of extracting a single field. Returns `None` when the account has never been touched at the queried batch, matching the semantics of a non-existing-slot `zks_getProof` result. Used by https://github.com/antoniolocascio-bot/prividium-zk-selective-disclosure to build `balance_of` / `observable_bytecode_hash` witnesses from Prividium RPC without requiring a second trust root. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
antoniolocascio-bot
pushed a commit
to antoniolocascio-bot/prividium-zk-selective-disclosure
that referenced
this pull request
Apr 9, 2026
## Summary
Wires the host crate from a library-only prover/verifier into a
fully end-to-end tool that fetches witnesses from a live ZKsync OS
L2 RPC and verifies them against a live Ethereum L1 RPC, driven by
a CLI. Adds a local-setup/ directory that spins up anvil + a
patched zksync-os-server for offline testing.
## New host modules
- `rpc_wire.rs` — JSON wire-format types mirroring
`zksync_os_rpc_api::types::BatchStorageProof` and
`zksync_os_merkle_tree_api::flat::StorageSlotProof` one-to-one.
We deliberately redefine these rather than taking a path dep on
`zksync_os_rpc_api`, because its transitive dep graph pulls in a
zksync-airbender version that conflicts with the one
`airbender-host` uses. Four snapshot tests lock in the exact
camelCase shape + the `type: existing | nonExisting` tag.
- `disclosure_request.rs` — high-level `DisclosureRequest` enum
with one variant per v0 statement (BalanceOf,
ObservableBytecodeHash, TxInclusion). This is what the CLI and
any user of `prove_from_source` passes in.
- `witness_source.rs` — `WitnessSource` trait. Uses `impl Future +
Send` in the trait signature to keep the returned future `Send`
(required by `prove_from_source`'s block-on). Also ships an
in-memory `MockWitnessSource` for tests.
- `rpc_l1.rs` — `RpcL1Source`: an `L1Source` that calls
`diamondProxy.storedBatchHash(uint64)` via alloy. Blocks on an
internal tokio runtime so the sync `L1Source` trait doesn't
leak async to callers.
- `rpc_l2.rs` — `RpcWitnessSource`: a `WitnessSource` that:
- calls `zks_getProof` to get Merkle paths + state commitment
preimage + L1 verification data,
- calls `zks_getAccountPreimage` (the new method from
matter-labs/zksync-os-server#1161) to get the 124-byte
`AccountProperties` preimage,
- for `tx_inclusion`, walks 256 blocks via
`eth_getBlockByNumber(full=true)`, converts each header
field-by-field into our core `BlockHeader`, and locates the
target tx in the rolling-hash window.
## Prover / verifier wiring
- `prover::prove_from_source<W: WitnessSource>` — new helper that
fetches a witness via the source, blocks on its async call from
a local tokio runtime, and feeds the resulting `ProveRequest`
into the existing `prove()`. New `ProveFromSourceError` cleanly
separates witness-fetch failures from prover-side failures.
## CLI
`host/src/main.rs` is now a full clap-based CLI with three
subcommands:
- `prove balance-of | observable-bytecode-hash | tx-inclusion`
— fetches a witness via `RpcWitnessSource`, runs the airbender
dev prover, writes the serialized `ProofBundle` to disk.
- `verify` — reads a bundle from disk, queries L1 via
`RpcL1Source`, runs the airbender dev verifier, prints a typed
`VerifiedDisclosure`.
- `inspect` — human-readable dump of a bundle file, no RPC calls.
## Local setup
`local-setup/run_local.sh` delegates to the server's own
`run_local.sh` pointing at `local-chains/v30.2/default`, after
checking that the sibling zksync-os-server checkout is on the
`prividium-sd-account-preimage-rpc` branch (needed until PR #1161
merges). `local-setup/README.md` documents the branch setup and
shows a full end-to-end CLI walkthrough.
## Tests
New `host/tests/witness_source.rs` — 4 integration tests that
exercise `DisclosureRequest → MockWitnessSource::fetch →
prove_from_source → verify_bundle → VerifiedDisclosure` end to
end for all three statements, plus a "not registered" error case.
Combined with the existing tests, the total is:
- 69 `prividium-sd-core` unit tests
- 18 `prividium-sd-test-fixtures` tests (9 unit + 9 integration)
- 6 host library unit tests (4 rpc_wire snapshots + 2 mock witness
source)
- 8 `host/tests/end_to_end.rs` (pre-existing)
- 5 `host/tests/statements.rs` (pre-existing)
- 4 `host/tests/witness_source.rs` (new)
- **110 total**
All green, all RPC-free — the real `RpcL1Source` /
`RpcWitnessSource` / CLI paths are exercised manually via
`local-setup/run_local.sh` against a live local setup.
## Notes
- The bundle format is unchanged; the new RPC pipeline just
produces the same `ProveRequest → prove() → ProofBundle` flow.
- No new dependency on any server crate: the wire types are
redefined in `host/src/rpc_wire.rs` and snapshot-tested against
hand-written JSON that matches the upstream shape.
- `core/` and `guest/` are untouched.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
zks_getAccountPreimage(address, batchNumber) -> Option<Bytes>JSON-RPC method under the existingzksnamespace. It returns the 124-byteAccountProperties::encoding()blob for the given account at the end of the specified L1 batch.Why
Any client that wants to prove claims about individual
AccountPropertiesfields (balance, nonce, observable bytecode hash, versioning data, …) against the Merkle-proof-verified tree value needs the exact 124-byte preimage, because the state tree stores onlyblake2s(AccountProperties::encoding())at the account-properties slot. The Merkle proof returned byzks_getProofcovers that hash, but not the preimage it commits to.Partial reconstruction from the existing public surface (
eth_getBalance,eth_getCode,eth_getTransactionCount) is not sufficient:versioning_data,bytecode_hash, andartifacts_lenare internal fields ofAccountPropertiesthat aren't otherwise exposed, and the resulting bytes wouldn't blake2s-hash to the tree value. This is particularly important for zk-based tooling (selective disclosure, light clients, cross-chain bridges reading ZKsync OS state) where trusting RPC responses directly defeats the purpose.What
Thin wrapper around the existing
path that
eth_getBalance/eth_getCodeetc. already rely on internally. The new method simply returnsBytes::copy_from_slice(&props.encoding())instead of extracting a single field:lib/rpc_api/src/zks.rs: adds thegetAccountPreimagemethod to theZksApitrait (under the existingzksnamespace).lib/rpc/src/zks_impl.rs: implementsget_account_preimage_implusingViewState::get_account, returningNonewhen the account doesn't exist at the queried batch (same semantics as a non-existing-slotzks_getProofresult).No new deps, no new fields on existing response types, no schema changes.
Tests
cargo nextest run -p zksync_os_rpc -p zksync_os_rpc_api— 14/14 passing locally.cargo clippy --all-targets --all-features --workspace --exclude zksync_os_integration_tests -- -D warnings— clean.cargo fmt --all -- --check— clean.I haven't added a dedicated RPC integration test in this PR because the path being exposed is the exact same one
eth_getBalance/eth_getCodealready cover (they go throughViewState::get_accountand then extract a field), so any regression would already be caught by those paths. Happy to add one if reviewers prefer.Context
The canonical user of this RPC is https://github.com/antoniolocascio-bot/prividium-zk-selective-disclosure — a tool that generates zero-knowledge proofs of individual Prividium account facts bound to an L1 batch commitment. That tool needs to hash the preimage bytes inside a zk circuit, so fetching the fields individually over RPC is not an option.
🤖 Generated with Claude Code