A privacy-preserving location guessing game built with Fully Homomorphic Encryption (FHE) using Zama's technology. Players guess locations from 360° panoramic views while their coordinates remain completely encrypted throughout the entire process, enabling fair competition without revealing sensitive location data.
- 🔐 Full Privacy: Coordinates are encrypted using FHE before leaving your device
- 🌐 360° Panoramic Views: Immersive Street View-style exploration using Pannellum
- ⛓️ Blockchain Integration: Smart contracts handle encrypted distance calculations on Ethereum Sepolia
- 🎯 Real-time Results: Instant distance feedback without revealing actual coordinates
- 🔍 Interactive Map: Click-to-guess interface with MapLibre GL
- 💳 Web3 Wallet Integration: Connect with MetaMask, WalletConnect, and more via RainbowKit
- 🏆 Competitive Gaming: Fair scoring system based on Euclidean distance approximation
- 🔄 Live Updates: Real-time game state synchronization across all players
- Next.js 15 - React framework
- TypeScript - Type safety
- Tailwind CSS - Styling
- MapLibre GL - Interactive maps
- RainbowKit - Wallet connections
- Radix UI - Accessible components
- Ethereum - Smart contract platform
- Hardhat - Development environment
- Ethers.js - Blockchain interaction
- Zama FHE - Fully Homomorphic Encryption
- Zama fhEVM - FHE-enabled smart contracts
- Relayer SDK - FHE encryption/decryption
- EIP-712 - Structured data signing
┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Frontend │ │ Relayer │ │ Smart Contract │
│ │ │ Service │ │ │
│ ┌─────────────┐ │ │ │ │ ┌─────────────┐ │
│ │ Encrypt │◄┼────┼──────────────┼────┼►│ Calculate │ │
│ │ Coordinates │ │ │ Zama FHE │ │ │ Distance │ │
│ └─────────────┘ │ │ │ │ └─────────────┘ │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ │ │ ┌─────────────┐ │
│ │ Decrypt │◄┼────┼──────────────┼────┼►│ Return │ │
│ │ Result │ │ │ │ │ │ Encrypted │ │
│ └─────────────┘ │ │ │ │ └─────────────┘ │
└─────────────────┘ └──────────────┘ └─────────────────┘
- Client-Side Encryption: Your guess coordinates are encrypted using Zama's FHE technology directly in your browser
- Encrypted Computation: Smart contract performs distance calculations on encrypted data without ever decrypting it
- Private Results: Distance is computed without revealing your guess coordinates, target coordinates, or intermediate calculations
- Zero Knowledge: Even the smart contract, blockchain validators, and other players never see your actual coordinates
- Verifiable Security: All operations are cryptographically verifiable while maintaining complete privacy
// Coordinates are scaled to preserve precision
const latInt = Math.round(latitude * 100000);
const lngInt = Math.round(longitude * 100000);
// Encrypted using Zama's FHE libraries
const input = fhevmInstance.createEncryptedInput(contractAddress, userAddress);
input.add32(latInt); // Encrypted as 32-bit integers
input.add32(lngInt);
const encryptedInput = await input.encrypt();Our smart contract implements a simplified Euclidean distance calculation due to FHE computational constraints:
// Note: This is a simplified approximation, not true geographic distance
function calculateDistance(
euint32 lat1, euint32 lng1, // Player guess (encrypted)
euint32 lat2, euint32 lng2 // Target location (encrypted)
) internal pure returns (euint32) {
euint32 latDiff = TFHE.sub(lat1, lat2);
euint32 lngDiff = TFHE.sub(lng1, lng2);
// Sum of squares calculation (encrypted)
euint32 latSquared = TFHE.mul(latDiff, latDiff);
euint32 lngSquared = TFHE.mul(lngDiff, lngDiff);
return TFHE.add(latSquared, lngSquared); // Returns sum of squares
}Since FHE currently doesn't support square root operations, we handle the final calculation on the frontend:
// Contract returns sum of squares of coordinate differences
const sumOfSquares = Number(decryptedValue);
// Calculate Euclidean distance in scaled coordinate units
const distanceInScaledUnits = Math.sqrt(sumOfSquares);
// Convert back to degrees
const distanceInDegrees = distanceInScaledUnits / 100000;
// Rough approximation: 1 degree ≈ 111 km
// Note: This is not perfectly accurate for all global locations
const approximateDistanceInKm = distanceInDegrees * 111;The ideal geographic distance calculation would use the Haversine formula:
a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
c = 2 ⋅ atan2( √a, √(1−a) )
d = R ⋅ c
However, FHE currently doesn't support:
- Trigonometric functions (sin, cos, atan2)
- Square root operations
- Complex mathematical operations
- Euclidean Distance: We use simplified Euclidean distance instead of great-circle distance
- Linear Approximation: 1 degree ≈ 111 km (varies by latitude but provides consistent scoring)
- Scaled Arithmetic: All calculations use integer arithmetic with 100,000x scaling for precision
- Frontend Square Root: Square root calculation happens after FHE decryption on the client
- Global Variations: Our approximation is less accurate near poles and more accurate near the equator
- Consistent Scoring: Despite inaccuracy, all players are scored using the same method, ensuring fairness
- Future Improvements: As FHE technology evolves, we can implement more sophisticated distance calculations
User Input: (40.7128, -74.0060)
↓
Scaling: (4071280, -7400600)
↓
FHE Encryption: Zama's euint32 ciphertext
↓
Smart Contract: Encrypted arithmetic operations
↓
Encrypted Sum of Squares: Still encrypted
↓
User Decryption: Using private key + EIP-712 signature
↓
Frontend Processing: Math.sqrt() + geographic approximation
↓
Final Distance: ~1,247 km (example)
- Contract Address:
0xAf52747676ae6e277f63760a25BaCe70D559A0A0 - Network: Ethereum Sepolia Testnet
- Chain ID: 11155111
- RPC Endpoint:
https://ethereum-sepolia-rpc.publicnode.com - Block Explorer: View on Sepolia Etherscan
function createRound(
string calldata panoramaUrl,
bytes calldata encryptedLat,
bytes calldata encryptedLng,
bytes calldata inputProof
) external returns (uint256 roundId)
function submitGuess(
uint256 roundId,
bytes calldata encryptedLat,
bytes calldata encryptedLng,
bytes calldata inputProof
) external returns (bytes32 encryptedDistance)
function getCurrentRound() external view returns (uint256)
function getRound(uint256 roundId) external view returns (Round memory)- Input Validation: All encrypted inputs require cryptographic proofs
- Access Control: Players can only decrypt their own results
- Replay Protection: EIP-712 signatures prevent replay attacks
- Scaling Consistency: All coordinates use consistent 100,000x scaling
- Efficient FHE Operations: Minimized encrypted operations to reduce gas costs
- Batch Processing: Multiple operations combined where possible
- Event Emissions: Comprehensive event logging for frontend synchronization
- Node.js 18+
- npm or yarn
- MetaMask or compatible Web3 wallet
- Clone the repository
git clone https://github.com/kocaemrefhe-geoguessr.git
cd fhe-geoguessr- Install dependencies
cd website
npm install- Set up environment variables
cp .env.example .env.local
# Add your configuration- Start the development server
npm run devOpen http://localhost:3000 with your browser to see the result.
- Deploy smart contracts (optional)
cd ../contracts
npx hardhat compile
npx hardhat deploy --network sepolia- Connect Wallet: Click "Connect Wallet" and choose your preferred wallet
- View Panorama: Explore the 360° view to understand the location
- Make Guess: Click "Make Guess" to open the world map
- Select Location: Click anywhere on the map to place your guess
- Submit: Click "Submit Encrypted Guess" to process your answer
- Wait for Results: Watch the FHE encryption/decryption process
- See Distance: Get your distance result in kilometers
# WalletConnect
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=xxxxxx
# Blockchain Configuration
NEXT_PUBLIC_RPC_URL=https://sepolia.infura.io/v3/your_key
NEXT_PUBLIC_CONTRACT_ADDRESS=0x...
# Application Settings
NEXT_PUBLIC_APP_NAME=FHE GeoGuessr- Sepolia Testnet:
0xAf52747676ae6e277f63760a25BaCe70D559A0A0
cd contracts
npx hardhat testcd website
npm testnpm run test:integration- Objective: Analyze the 360° panoramic view and guess the exact location on Earth
- Scoring: Lower distance = better score (measured in kilometers)
- Privacy: Your exact coordinates are never revealed to anyone during the game
- Fairness: All players compete under identical privacy-preserving conditions
- Distance Calculation: Euclidean distance approximation using encrypted coordinates
- Accuracy Range: 0-20,000 km (capped at half Earth's circumference)
- Precision: Results shown to 2 decimal places (e.g., 1,247.83 km)
- Consistency: All players scored using identical mathematical methods
- FHE Limitations: True geographic distance requires trigonometric functions not yet available in FHE
- Coordinate Scaling: All coordinates scaled by 100,000x for integer arithmetic precision
- Approximation Method: Linear degree-to-kilometer conversion (1° ≈ 111 km)
- Global Variance: Accuracy varies by latitude but scoring remains fair and consistent
- Complete Confidentiality: Neither target locations nor player guesses are ever exposed
- Cryptographic Security: All computations performed on encrypted data
- Decentralized Verification: Results verifiable without compromising privacy
- Zero-Knowledge Gaming: Players learn their distance without revealing their strategy
- Basic FHE integration
- 360° panoramic views
- Distance calculation
- Web3 wallet integration
- Leaderboard system
- Multiple difficulty levels
- Tournament mode
- Social sharing
- NFT rewards for winners
- Multiplayer competitions
- Custom location uploads
- Mobile app
We welcome contributions!
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
This project uses cutting-edge FHE technology to ensure complete privacy. However, please note:
- This is experimental technology
- Use testnet funds only
- Report security issues responsibly
This project is licensed under the MIT License - see the LICENSE file for details.
This project was built for the Zama Developer Program, showcasing the power of Fully Homomorphic Encryption in creating privacy-preserving applications.
- Documentation: docs.zama.ai
- Discord: Zama Community
- Issues: GitHub Issues
Made with ❤️ and 🔐 by Emre]
Powered by Zama's Fully Homomorphic Encryption