Solution: LP-0003 Private Allowlist / Airdrop Distributor - #126
Open
edenbd1 wants to merge 3 commits into
Open
Conversation
✅ Validation passedA reviewer will assess against the prize criteria. Automated check. See solution template and TERMS. |
The deployment moves to LEZ v0.2.4. A guest's ImageID depends on the pinned revision, so both programs are new binaries at new content-addressed deploy transactions, and the two distributions and all 23 claims are re-created on chain rather than carried over. All 23 are verified live and privacy-preserving over RPC, and all 23 marker accounts re-derived from the verifier ImageID and confirmed owned by it. The anchor check is tightened while the deployment was re-keying anyway: `claim` now requires the distribution account's owner to equal the verifier itself, rather than merely to be non-default. The published IDL is unchanged. Corrections, each found by re-checking a claim this document makes: - `lee/state_machine/src/program.rs` does not exist; the file is `program/mod.rs`, and the split predates the release this targets, so the citation never resolved. `execution_state.rs:149` sat four lines above the `env::verify` it names. - The explorer does index these transactions; it lags by about an hour and three quarters. It does not drop them. And what it shows for a claim — type, proof size, marker address, nothing naming a distribution or an address — is the privacy property rendered by a third party, so this now says that instead of explaining an absence. - The claim cost is 318,242 user cycles, re-measured against the current binary. Proving wall-clock is no longer quoted as a fixed number: it moves by half again with machine contention. - 30 tests across the workspace, not 29; 25 adversarial rejections in the executor suite, not 28. The demo video is re-recorded against this deployment, since the previous one showed the superseded ImageIDs on screen.
The verify snippet passes a claim tx, a nullifier and a distribution id. Only the first is a transaction; getTransaction returns null on the other two. Worth stating here rather than only in the repository docs, since a reviewer checking the hashes would otherwise hit two nulls and reasonably wonder.
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.
A distributor commits an eligibility set on chain. An eligible recipient claims
their allocation without revealing which entry is theirs — not to observers, and
not to the distributor.
solutions/LP-0003.mdWhat is verified on chain
A claim travels on LEZ's privacy-preserving path, carrying a real STARK receipt
the sequencer checks against the node-pinned
PRIVACY_PRESERVING_CIRCUIT_ID.What lands is a single marker account whose address is
SHA256(prefix ‖ distribution_id ‖ nullifier), where the nullifier is derivedfrom the recipient's secret. An observer who knows every candidate address still
cannot compute the nullifier, so no marker maps back to a recipient.
Evidence, on the current public testnet
59c2160b40c5d0f4cce01fd89e7755dbafd9c7d088a071d6f6fd3a10cbbea7c57b16e471b35ce8c718e066d80a8198f8831ebc7b6704583ddd28bb287092e34c441ccd15e7b5eac388a0849481e95db409f1b6f23a202b6ee1a3ce37ae112c86Each hash links to its page on the block explorer. Both deploys and all 23 claims render there; a claim shows as
Privacy-Preserving Transactionwith its proof size, and nothing naming a distribution or a recipient.The two program hashes are
SHA256(borsh(bytecode))of the binaries committed inthe repository, so they can be recomputed without trusting this table.
Two distributions and 23 privacy-preserving claims (12 + 11) are live, listed
with their nullifiers in
artifacts/e2e/claims.tsv.Each of the 23 marker accounts is derived from the verifier's ImageID and the
claim's nullifier, and each is owned by the verifier — which is the part no
transaction lookup can fake, and what
./scripts/verify-onchain-claim.shends onafter five checks.
Beyond the unit tests
docs/onchain-audit.mdrecords three adversarial demonstrations run against thelive deployed programs rather than a local harness: a claim that does not
genuinely prove membership, one that redirects its allocation, and one that
replays a spent nullifier. All three fail at proof generation, so none reaches a
block.
scripts/adversarial-onchain.shre-runs all three against whatever isdeployed, and fails the run if any of them produces a transaction instead of a
rejection.
On the explorer
The explorer is a separate index and reaches a transaction about an hour and
three quarters after the sequencer does — measured, not assumed, so a hash
submitted recently is not there yet while
getTransactionalready has it.scripts/check-explorer.pyre-measures that by rendering the pages headless withan impossible hash as the control, because the explorer is a WASM app that
returns an identical shell for every URL and cannot be probed with
curl.Once indexed, a claim renders its transaction type, its proof size and the marker
address — and nothing naming a distribution or a recipient. That is the privacy
property, rendered by a third party.
Against the criteria
30 tests, CI green, including a workflow that runs the whole lifecycle against a
real standalone LEZ sequencer with
RISC0_DEV_MODE=0. CU cost is measured perinstruction by replaying the sequencer's own execution of the deployed binary:
318,242 user cycles for a claim, 1.56% of the public budget. The Basecamp module
ships as a
.lgxwith darwin-arm64 and linux-amd64 variants;scripts/package-lgx.py --verifyrecomputes every manifest hash from thearchive's own contents, and the video shows that check passing.
The video shows a fresh claim proved and submitted during the recording, with
RISC0_DEV_MODE=0visible before any proving starts, and the five checks passingagainst it afterwards. It is a single take; the stretch where the proof runs and
nothing on screen changes is played at eight times speed, and nothing is cut.
Happy to address anything in review.