diff --git a/solutions/LP-0003.md b/solutions/LP-0003.md new file mode 100644 index 00000000..29f5275c --- /dev/null +++ b/solutions/LP-0003.md @@ -0,0 +1,125 @@ +# Solution: LP-0003 — DistributionX + +**Submitted by:** Timidan + +## Summary + +DistributionX is a private allowlist airdrop flow for Logos Execution Zone (LEZ). A distributor generates an encrypted allowlist bundle, commits a Merkle root chain-side, funds a vault, and enables recipients to claim with a privacy-preserving zero-knowledge proof. + +The privacy objective is to avoid exposing the eligible recipient row, row salt, claim signature, and Merkle path in public execution. DistributionX uses `claim_ppe` via LEZ Privacy Preserving Transactions (`send_privacy_preserving_tx`) so the witness is private while keeping the on-chain transaction verifiable. + +## Repository + +- **Repo:** https://github.com/Timidan/dist-x +- **Current source and documentation:** [c629c6c7bbd4b3aa56d4357f60817d49438e044b](https://github.com/Timidan/dist-x/commit/c629c6c7bbd4b3aa56d4357f60817d49438e044b) +- **Release:** [v0.1.0](https://github.com/Timidan/dist-x/releases/tag/v0.1.0) +- **Release source:** [74f81ab9ee74ba533d3a8fa01cba9f67153f6385](https://github.com/Timidan/dist-x/commit/74f81ab9ee74ba533d3a8fa01cba9f67153f6385) +- **Verifier source used by the evidence run:** [fb61565fd7f8d3409ff65f7e2f4a7297cd56078a](https://github.com/Timidan/dist-x/commit/fb61565fd7f8d3409ff65f7e2f4a7297cd56078a) +- **Demo video:** https://youtu.be/w0TL22pnkqo +- **Default-branch CI run:** https://github.com/Timidan/dist-x/actions/runs/34163950395 + +The `v0.1.0` release artifacts were built from `74f81ab9...`. The repository has since advanced to `c629c6c...` for documentation and CI maintenance; the evidence manifest records `fb61565...` as the verifier source used for the captured testnet run. + +## Approach + +DistributionX is implemented as a Rust/Logos program + Basecamp client + SDK module with these steps: + +1. **Bundle ingest and commitment** + - The distributor reads CSV rows and validates input structure. + - Recipient rows are encrypted and committed as Merkle-based on-chain state (buckets and metadata). +2. **Claim generation** + - A claimant reconstructs their row locally, builds witness data, and generates a Risc0 proof. + - Claim is submitted with `RISC0_DEV_MODE=0`. +3. **Privacy-preserving execution path** + - The proof is transported in `claim_ppe` through LEZ PPE, which does not include witness fields in public tx instruction/data. +4. **Settlement and uniqueness** + - The submitted native LEZ flow completes the claim through `claim_ppe`. + - Optional custom-token settlement is a separate follow-up transaction and was not used in the submitted testnet run. + - Nullifier PDAs prevent duplicate claims per eligibility row. +5. **Submission consistency** + - All artifacts are pinned and published: evidence logs, manifests, README, bench report, architecture, and release packages. + +## Success Criteria Checklist + +**Functionality** + +- [x] The distributor commits only a fixed-depth Merkle root and public amount-bucket table on-chain; recipient rows are delivered in per-recipient encrypted bundles. +- [x] An eligible recipient submits `claim_ppe` through LEZ privacy-preserving execution without placing the address, salt, signature, or Merkle path in the public transaction message. +- [x] A nullifier PDA keyed by distribution and row salt prevents a second claim and returns `E_ALREADY_CLAIMED` (code 6). +- [x] Observer unlinkability is defined within an amount bucket: observers see the root, bucket id, nullifier, destination commitment, timing, and transaction metadata, but not the private witness. Singleton or small buckets, timing correlation, wallet-funded gas, or out-of-band data can reduce that anonymity set. +- [x] The distributor knows the original CSV and salts and can retain a nullifier-to-row mapping. The local adapter, claimant device, wallet seed, and private `claim.tx` are trusted; DistributionX protects against public-chain observers, not a malicious distributor or compromised claimant host. +- [x] The reference integration is deployed on LEZ testnet as program `4bf08c88a91871ecf69ff08af42591a597c51142cbc1f9c6fbbb7d2e888d9ee3` ([deployment transaction](https://explorer.testnet.lez.logos.co/transaction/2186b9ba9e95e4926f2800e88b5d0653bda3d1669414f0a19c6daf0798576181)). +- [x] Two native-token distributions completed ten included `claim_ppe` transactions each; all 27 approved writes and capture-time RPC responses are committed. +- [x] The public repository includes end-to-end instructions, architecture, privacy model, benchmarks, testnet evidence, and reproducible scripts. + +**Usability** + +- [x] `crates/distributionx-client` provides the Rust client SDK, and `distributionx_client_module` exposes the workflow as a Logos core module. +- [x] The Basecamp GUI has local build/launch instructions and two load-tested release assets: `distributionx-client.lgx` and `DistributionX-ui.lgx`. +- [x] `idl/distributionx.idl.json` is the SPEL IDL; generated Rust and C clients are checked in CI. + +**Reliability** + +- [x] CLI proof failures return stable error identifiers; Basecamp translates them into a visible failure message and states that the claim was not submitted, so the claimant can correct the setup and retry. +- [x] Claim validation, native payout, and nullifier creation are atomic. A failed proof, rejected claim, insufficient vault, or failed transfer does not persist the nullifier. +- [x] The SPEL IDL documents deterministic program codes 1-17, including `E_BAD_PROOF` (5), `E_ALREADY_CLAIMED` (6), `E_VAULT_INSUFFICIENT` (7), and `E_TRANSFER_FAILED` (8). + +**Performance** + +- [x] LEZ v0.2.4 operation costs and proof times are documented below and in the machine-readable benchmark capture. Public-testnet RPC proves inclusion but does not expose per-operation CU, so the CU values come from the pinned standalone LEZ runtime. + +**Supportability** + +- [x] The pinned program and two distributions are deployed on LEZ public testnet with committed transaction evidence. +- [x] CI runs Rust, Logos module, Basecamp package, installed-LGX, and standalone LEZ `RISC0_DEV_MODE=0` checks on the default branch. +- [x] The README covers deployment, program addresses, CLI usage, Basecamp launch, packaging, and evidence capture. +- [x] `scripts/e2e.sh ci-localnet` is the reproducible real-proof standalone demo and rejects a duplicate claim. +- [x] The narrated demo video shows the pinned revision, real proof generation, successful claim, and duplicate rejection. +- [x] Release, verifier, and current documentation revisions are identified separately and pinned explicitly. + +## FURPS Self-Assessment + +### Functionality + +The implementation covers distribution creation, encrypted eligibility, on-chain initialization, private proof submission, native `claim_ppe` completion, and nullifier enforcement. Optional custom-token settlement is separate from the submitted native claim flow and was not exercised in this evidence run. + +### Usability + +Claimants can use the CLI or the Basecamp GUI; module builders can use the Rust client crate or Logos core module. The release includes both LGX packages, and the SPEL IDL plus generated clients are committed. Helper scripts require Linux or macOS and Bash 4.x or newer; they are not portable POSIX `sh` scripts. + +### Reliability + +The UI keeps proof generation and submission as separate states, displays actionable errors, and never labels a failed backend response as success. On-chain validation, native payout, and nullifier creation are atomic, so rejection leaves the row retryable. Stable program codes are documented in the SPEL IDL and tested, including bad proof, duplicate claim, insufficient vault, and transfer failure. + +### Performance + +The pinned standalone LEZ v0.2.4 measurements are: + +| Operation | Compute units | Measurement source | +|---|---:|---| +| `init_airdrop` | 442,994 | Sequencer transaction execution | +| `fund` | 447,471 | Sequencer transaction execution | +| `claim_ppe` | 5,154,242 | Risc0 `SessionInfo::cycles` for the exact funded pre-state | +| `close` | 504,505 | Sequencer transaction execution | + +For the reviewer fixture, real eligibility proving took 19m20s and real PPE claim composition took 26m12s on the recorded CPU with `RISC0_DEV_MODE=0`. The separate 30-claimant release-build benchmark took 39-42 minutes. Public-testnet RPC does not expose a distinct CU field, so these costs are reproducible pinned-runtime measurements rather than claims about public-testnet RPC data. + +### Supportability + +The package is release-ready (`v0.1.0`) with an explicit manifest, run artifacts, architecture docs, and support script coverage for deploy/claim/package flows. Release, verifier, and current documentation revisions are pinned separately so their lineage is unambiguous. + +## Supporting Materials + +- Evidence index: https://github.com/Timidan/dist-x/blob/c629c6c7bbd4b3aa56d4357f60817d49438e044b/docs/TESTNET_EVIDENCE.md +- Evidence manifest: https://github.com/Timidan/dist-x/blob/c629c6c7bbd4b3aa56d4357f60817d49438e044b/docs/testnet-evidence/v0.1.0/manifest.json +- RPC snapshots: https://github.com/Timidan/dist-x/tree/c629c6c7bbd4b3aa56d4357f60817d49438e044b/docs/testnet-evidence/v0.1.0/rpc +- README: https://github.com/Timidan/dist-x/blob/c629c6c7bbd4b3aa56d4357f60817d49438e044b/README.md +- Writeup: https://github.com/Timidan/dist-x/blob/c629c6c7bbd4b3aa56d4357f60817d49438e044b/docs/WRITEUP.md +- Bench report: https://github.com/Timidan/dist-x/blob/c629c6c7bbd4b3aa56d4357f60817d49438e044b/docs/bench/REPORT.md +- CU capture: https://github.com/Timidan/dist-x/blob/c629c6c7bbd4b3aa56d4357f60817d49438e044b/docs/bench/lez-v0.2.4-cu.json +- Architecture: https://github.com/Timidan/dist-x/blob/c629c6c7bbd4b3aa56d4357f60817d49438e044b/DistributionX.system-architecture.excalidraw +- Terms: https://github.com/logos-co/lambda-prize/blob/master/TERMS.md + +## Terms & Conditions + +By submitting this solution, I confirm that I have read and agree to the [Terms & Conditions](../TERMS.md).