Note: zkip is brand new and actively under development. Things will change and bugs may exist. If you find any bugs or have any feature requests, please open an issue.
zkip is a zero-knowledge proof library for proving a user's IP address is not from a specified set of countries without revealing the actual IP address. Built with SP1 zkVM.
Many businesses and developers end up storing IP addresses for various reasons:
- Regulatory compliance (tax laws, content licensing, gambling restrictions)
- Proving user location to auditors
- Fraud prevention and geo-restrictions
- Analytics and service customization
But storing IP addresses creates privacy concerns and GDPR obligations. What if you could prove location without storing the IP?
(For example: In France, digital service providers must charge VAT on all sales unless they can prove the customer's location. This typically requires storing IP addresses, which is a privacy concern.)
zkip's solution: Generate a zero-knowledge proof that verifies "this IP is not from countries X, Y, Z" without revealing or storing the actual IP address. You get verifiable location proofs while keeping user data private.
┌─────────────────────────────────────────────────────────────────────────────┐
│ ARCHITECTURE │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────┐ POST /prove ┌──────────────────┐
│ │ {excluded: ["FR","DE"]} │ │
│ User │ ─────────────────────────▶ │ Your API │
│ (Browser) │ │ (zkip) │
│ │ │ │
│ IP: hidden │ │ Extracts IP from │
│ │ │ TCP connection │
└──────────────┘ └────────┬─────────┘
▲ │
│ │ IP + country ranges
│ │ (private inputs)
│ ▼
│ ┌──────────────────┐
│ │ │
│ { │ SP1 Prover │
│ is_excluded: true, │ (local or │
│ proof: "0xabc...", │ network) │
│ timestamp: "..." │ │
│ } │ Runs ZK circuit: │
│ │ IP ∉ excluded? │
└────────────────────────────────────┴──────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ WHAT GETS STORED │
├─────────────────────────────────────────────────────────────────────────────┤
│ ✅ Cryptographic proof │
│ ✅ Boolean result (is_excluded) │
│ ✅ User identifier (e.g., wallet address) │
│ ✅ Timestamp │
│ │
│ ❌ IP address (never stored) │
│ ❌ Actual country (never revealed) │
└─────────────────────────────────────────────────────────────────────────────┘
sequenceDiagram
participant User as User (wallet: 0x123...)
participant API as Your API (zkip)
participant Prover as SP1 Prover
User->>+API: POST /prove<br/>{excluded: ["FR", "DE"], wallet: "0x123..."}
Note over API: Extract IP from TCP connection<br/>Load IP to country range table
API->>+Prover: Private inputs: IP + full range table<br/>Public input: excluded countries
Note over Prover: ZK Circuit executes:<br/>1. Lookup IP in range table<br/>2. Check if country in excluded list<br/>3. Output: is_excluded = true/false
Prover-->>-API: proof + is_excluded
Note over API: Discard IP from memory
API-->>-User: {proof, is_excluded, timestamp}
Note over User: Store proof for compliance audit<br/>No IP ever stored
zkip/
├── lib/ # Shared code (types and functions used by both program and script)
│ └── src/lib.rs # IP range types, country check logic
├── program/ # The ZK program (compiles to RISC-V, runs inside SP1 zkVM)
│ └── src/main.rs # Reads IP, checks ranges, outputs boolean
├── script/ # CLI for testing and generating proofs
│ └── src/bin/
│ ├── main.rs # Execute or prove the program
│ ├── evm.rs # Generate EVM-compatible proofs (Groth16/PLONK)
│ └── vkey.rs # Export verification key for on-chain use
| Crate | Purpose | Compilation Target |
|---|---|---|
| lib | Shared types and functions (used by both) | Standard Rust (testable) |
| program | ZK circuit that runs inside SP1 zkVM | RISC-V (via cargo prove) |
| script | CLI to trigger execution/proving | Standard Rust |
The lib crate is optional but recommended. It lets you share types (like PublicValuesStruct) between the program and script, and test your logic without compiling to RISC-V.
cd program && cargo prove buildOr let it build automatically when running the script.
Test the logic without generating a proof:
cargo run --release -- --execute --ip 8.8.8.8 --exclude FR,USThis runs the ZK circuit locally and outputs the result without generating a cryptographic proof.
cargo run --release -- --prove --ip 8.8.8.8 --exclude FRLocal proving is slow (minutes to hours depending on hardware). For production, use the network.
The Succinct Prover Network provides fast, distributed proof generation.
Setup:
- Generate a key pair:
cast wallet new(or export from Metamask) - Get PROVE tokens on Ethereum Mainnet
- Deposit PROVE at Succinct Explorer
- Configure environment:
cp .env.example .envSP1_PROVER=network
NETWORK_PRIVATE_KEY=0x... # Your requester account private key- Run:
cargo run --release -- --prove --ip 8.8.8.8 --exclude FRFor on-chain verification (requires network or 16GB+ RAM locally):
# Groth16 (smaller proof, higher gas to generate)
cargo run --release --bin evm -- --ip 8.8.8.8 --exclude FR --system groth16
# PLONK (larger proof, no trusted setup)
cargo run --release --bin evm -- --ip 8.8.8.8 --exclude FR --system plonk| Flag | Description | Default |
|---|---|---|
--ip |
IP address to test | 8.8.8.8 |
--exclude |
Comma-separated country codes (ISO 3166-1 alpha-2) | FR |
--refresh |
Force refresh the GeoIP database | false |
--execute |
Run without proof (main.rs only) | - |
--prove |
Generate proof (main.rs only) | - |
--system |
Proof system: groth16 or plonk (evm.rs only) |
groth16 |
The CLI automatically fetches IP-to-country data from ip-location-db via jsDelivr CDN. The database is cached locally for 30 days. Use --refresh to force an update.
POST /prove
Request:
{
"excluded_countries": ["FR", "DE", "IT"], // Countries to prove absence from
"user_id": "0x123..." // Optional: wallet or identifier
}
Response:
{
"is_excluded": true, // IP not in any excluded country
"proof": "0xabc...", // ZK proof
"timestamp": "2025-12-18T12:00:00Z"
}
🚧 Proof of Concept
- IP range data structure (u32 start/end tuples)
- Multi-country exclusion logic
- ZK circuit implementation (SP1 zkVM)
- CLI with
--ip,--exclude,--refreshflags - Dynamic GeoIP database fetching (30-day cache)
- EVM-compatible proofs (Groth16/PLONK)
- REST API endpoint
- IP extraction from HTTP request
- Proof generation service
- Solidity verifier contract
- Contract deployment scripts
- Frontend integration
- Proof storage and retrieval
| Party | Sees IP? | Stores IP? |
|---|---|---|
| User | ✅ (their own) | N/A |
| Your Server | ✅ (transient in memory) | ❌ No |
| SP1 Prover Network | ✅ (during computation) | ❌ No |
Note: The SP1 Prover Network is a compute service, not a blockchain. Inputs are processed in memory and discarded after proof generation.
Original zkip code is licensed under the GNU Affero General Public License v3.0 only. If you run a modified version as a network service, you must offer its corresponding source to users as required by AGPLv3 section 13.
This repository was bootstrapped from Succinct Labs' MIT-licensed SP1 Project Template. Succinct's copyright and MIT notice remain in LICENSE-MIT. The committed country-code dataset has a separate CC BY-SA 4.0 license. See THIRD_PARTY_NOTICES.md for provenance and attribution.
Dependencies, including SP1, retain their respective licenses.