Repo for storing my Project Euler Rust solutions. Each solution encrypted and accompanied by a zk proof generated by RISC Zero's zkVM, proving its correctness. I know this is complete overkill and unnecessary but I thought it was cool.
- Each solution runs inside RISC Zero's zkVM, a RISC-V virtual machine
- The zkVM produces a receipt, which is a cryptographic proof that the program executed correctly and output a specific answer
- The receipt is tied to an image ID, a hash of the guest program binary. This commits to the code without revealing it
- Anyone with the receipt and image ID can verify the proof
The proof guarantees: "There exists a program (identified by this image ID) that, given this problem number, outputs this answer." You can confirm the answer is correct by checking it against Project Euler, but you cannot determine how it was computed.
Not all proofs might be available because they take a long time to generate, with which I'd rather not burden my silicon.
- Rust (stable)
- RISC Zero toolchain:
curl -L https://risczero.com/install | bash && rzup install
# Verify a single problem
cargo run -p verify -- 1
# Verify all proofs
cargo run -p verify -- allThere are three binaries in this workspace:
cargo run -p project-euler --release -- <problem_number>cargo run -p host -- <problem_number|all>cargo run -p verify -- <problem_number|all>Create src/problems/p###.rs (zero-padded, e.g. p019.rs) with one of these signatures:
pub fn solve() -> String // self-contained problems
pub fn solve_with_input(input: &str) -> String // problems needing external data (put input in inputs/p###.txt)The build script then auto-discovers new files and wires everything up. NOTE: Any change to the ELF binary, including adding new solutions, invalidates all existing proofs. I recommend just doing a few; 1,2, and 6 are quick to prove, for example.
| Problem | Rough proof time (m3 pro) |
|---|---|
| 1 | <10s |
| 2 | <10s |
| 3 | ~5h |
| 4 | not generated yet (tried for 6 hours and it didn't finish) |
| 5 | not generated yet |
| 6 | <10s |
| 7 | not generated yet |
| 8 | not generated yet |
| 9 | not generated yet |
| 10 | not generated yet |
| 11 | not generated yet |
| 12 | not generated yet |
| 13 | not generated yet |
| 14 | not generated yet |
| 15 | not generated yet |
| 16 | not generated yet |
| 17 | not generated yet |
| 18 | not generated yet |
| 19 | not generated yet |
| 20 | not generated yet |
| 21 | not generated yet |
| 22 | not generated yet |
| 23 | not generated yet |
| 27 | not generated yet |
| 34 | not generated yet |
| 35 | not generated yet |
| 50 | not generated yet |
| 67 | not generated yet |
| 92 | not generated yet |
zk-euler/
├── proofs/ # Cryptographic receipts
│ ├── image_id.json # Hash of the guest program
│ └── p001.bin ... # STARK proofs for each problem
├── verify/ # Public verifier
│ └── src/main.rs
├── host/ # Proof generator (encrypted)
│ └── src/main.rs
├── methods/ # zkVM guest build infrastructure
│ └── guest/src/main.rs # Guest entry point (encrypted)
├── src/ # Solution code (encrypted)
│ ├── main.rs # CLI: cargo run -p project-euler -- <n>
│ ├── lib.rs
│ ├── utils/ # Shared utilities
│ │ ├── primes.rs
│ │ ├── digits.rs
│ │ └── math.rs
│ └── problems/
└── inputs/ # Problem input data files