Privacy Protocol
This document details the privacy mechanisms used in Lunarys to ensure transaction confidentiality through Fully Homomorphic Encryption (FHE).
Privacy Goals
Lunarys achieves the following privacy properties through FHE:
- Amount Privacy: All transaction amounts remain encrypted on-chain
- Balance Privacy: Token balances never revealed in plaintext
- Reserve Privacy: Pool liquidity quantities stay confidential
- Vote Privacy: Governance vote weights and tallies encrypted
- Position Privacy: LP positions and rewards remain private
Fully Homomorphic Encryption (FHE)
What is FHE?
Fully Homomorphic Encryption allows computations to be performed directly on encrypted data without decrypting it. The results of these computations remain encrypted and can only be decrypted by authorized parties.
Key Properties:
- Compute on ciphertext without accessing plaintext
- Results are also encrypted
- Mathematical operations preserve correctness
- No intermediate decryption required
Zama fhEVM
Lunarys uses Zama's fhEVM, which brings FHE to Ethereum Virtual Machine:
Features:
- Native FHE operations in Solidity
- Encrypted integer types (
euint8,euint64,euint128) - Encrypted boolean type (
ebool) - Arithmetic operations on encrypted values
- Comparison operations returning encrypted results
- Conditional selection with encrypted conditions
How It Works:
- User encrypts data with Zama's public key (client-side)
- Encrypted data submitted to blockchain
- Smart contracts perform FHE operations on encrypted data
- Results remain encrypted on-chain
- Oracle service decrypts when explicitly requested
- Decryption requires threshold signatures (no single point of decryption)
Encryption Flow
Client-Side Encryption
// User encrypts amount before submitting
import { createInstance } from "fhevmjs";
const fhevm = await createInstance({ chainId, publicKey });
const input = fhevm.createEncryptedInput(contractAddress, userAddress);
input.add64(amountInWei); // Add 64-bit value
const encryptedInput = await input.encrypt();
// Submit to contract
await contract.deposit(
encryptedInput.handles[0], // Encrypted value handle
encryptedInput.inputProof // Zero-knowledge proof of encryption
);
Privacy Protection:
- Amount never sent in plaintext
- Network observers see only ciphertext
- Block explorers cannot read amounts
- Even validators cannot see values
On-Chain Storage
contract ConfidentialToken {
// Balance stored as encrypted value
mapping(address => euint64) private _balances;
function transfer(address to, euint64 encryptedAmount) external {
// All operations on encrypted values
_balances[msg.sender] = FHE.sub(_balances[msg.sender], encryptedAmount);
_balances[to] = FHE.add(_balances[to], encryptedAmount);
}
}
Storage Properties:
- All sensitive values stored as
euintXtypes - Cannot be read in plaintext from storage
- RPC calls return ciphertext, not plaintext
- Etherscan shows encrypted blobs
FHE Operations
Arithmetic Operations
All arithmetic done without decryption:
// Addition
euint64 sum = FHE.add(encryptedA, encryptedB);
// Subtraction
euint64 diff = FHE.sub(encryptedA, encryptedB);
// Multiplication
euint64 product = FHE.mul(encryptedA, encryptedB);
// Division
euint64 quotient = FHE.div(encryptedA, encryptedB);
Privacy Guarantee: Intermediate results never decrypted
Comparison Operations
Comparisons return encrypted booleans:
// Less than
ebool isLess = FHE.lt(encryptedA, encryptedB);
// Greater than
ebool isGreater = FHE.gt(encryptedA, encryptedB);
// Equality
ebool isEqual = FHE.eq(encryptedA, encryptedB);
// Greater than or equal
ebool isGTE = FHE.gte(encryptedA, encryptedB);
Privacy Guarantee: Comparison results remain encrypted
Conditional Operations
Select values based on encrypted conditions:
// If condition is true, return valueIfTrue, else valueIfFalse
euint64 result = FHE.select(
encryptedCondition, // ebool
valueIfTrue, // euint64
valueIfFalse // euint64
);
Use Cases:
- Conditional transfers
- Dynamic fee calculation
- Access control logic
- Voting outcome determination
Logical Operations
Boolean logic on encrypted values:
// AND
ebool result = FHE.and(encryptedBool1, encryptedBool2);
// OR
ebool result = FHE.or(encryptedBool1, encryptedBool2);
// NOT
ebool result = FHE.not(encryptedBool);
Permission System
Access Control for Encrypted Values
Each encrypted value has an Access Control List (ACL):
// Grant permission to an address
FHE.allow(encryptedValue, recipientAddress);
// Grant permission to contract itself
FHE.allowThis(encryptedValue);
// Grant permission to multiple addresses
FHE.allow(encryptedValue, address1);
FHE.allow(encryptedValue, address2);
Permission Rules:
- Only permitted addresses can use encrypted values
- Permissions required for all operations
- Transactions revert if permissions missing
- Temporary permissions during function execution
Decryption Permissions
For users to decrypt their own values:
// User can decrypt their balance if granted permission
const handle = await token.balanceOf(userAddress);
const decrypted = await fhevm.decrypt(handle, userAddress);
Requirements:
- Contract must grant permission via
FHE.allow() - User must sign decryption request
- Decryption happens client-side
- No on-chain decryption for user queries
Oracle-Based Decryption
When Decryption is Needed
Certain operations require plaintext values:
- Swap output amounts (for token transfers)
- Vote tally results (for proposal outcomes)
- Balance checks for compliance
Decryption Request Flow
// 1. Contract requests decryption
bytes32[] memory handles = new bytes32[](1);
handles[0] = FHE.toBytes32(encryptedValue);
uint256 requestId = FHE.requestDecryption(
handles,
this.callbackFunction.selector
);
// 2. Oracle decrypts off-chain (automatic)
// 3. Oracle calls callback with plaintext
function callbackFunction(
uint256 requestId,
bytes memory cleartexts,
bytes memory decryptionProof
) external {
// 4. Verify proof
FHE.checkSignatures(requestId, cleartexts, decryptionProof);
// 5. Decode plaintext
uint64 decryptedValue = abi.decode(cleartexts, (uint64));
// 6. Continue execution with plaintext
_processWithPlaintext(decryptedValue);
}
Oracle Security
Threshold Decryption:
- Multiple oracle nodes participate
- No single node can decrypt alone
- Requires threshold signatures (e.g., 3 of 5)
- Prevents single point of compromise
Proof Verification:
- Oracle provides cryptographic proof
- Contract verifies proof on-chain
- Invalid proofs rejected
- Ensures correctness of decryption
Privacy in Practice
PrivacyPool AMM
Encrypted Reserves:
euint64 private reserveA; // Never revealed
euint64 private reserveB; // Never revealed
Swap Calculation:
// All done on encrypted values
euint64 effectiveIn = _applyFee(amountIn);
euint64 newReserveIn = FHE.add(reserveIn, effectiveIn);
euint128 numerator = FHE.mul(
FHE.asEuint128(reserveIn),
FHE.asEuint128(reserveOut)
);
Masked Decryption: To prevent leaking reserve ratios:
- Generate random mask
- Multiply both numerator and denominator by mask
- Decrypt only masked denominator
- Divide masked numerator by decrypted masked denominator
- Mask cancels out, correct result obtained
- Original reserves never revealed
Confidential Governance
Encrypted Voting Power:
mapping(address => euint64) private _balances; // Total deposited
mapping(address => euint64) private _available; // Unlocked power
Vote Tallying:
// Add encrypted votes without decryption
proposal.forVotes = FHE.add(proposal.forVotes, encryptedWeight);
proposal.againstVotes = FHE.add(proposal.againstVotes, encryptedWeight);
Outcome Determination:
// Compare encrypted tallies
ebool forWins = FHE.gt(proposal.forVotes, proposal.againstVotes);
ebool quorumMet = FHE.gte(
FHE.add(proposal.forVotes, proposal.abstainVotes),
FHE.asEuint64(quorumThreshold)
);
// Only decrypt final result
ebool succeeded = FHE.and(quorumMet, forWins);
// requestDecryption(succeeded) -> returns bool
Privacy Guarantees
What Remains Private
Always Encrypted:
- Token balances
- Transfer amounts
- Pool reserves
- Swap inputs and outputs
- Vote weights
- Voting tallies
- LP positions
- Reward amounts
Never Decrypted On-Chain:
- Individual user balances
- Specific trade amounts
- Pool liquidity quantities
- Individual votes
What is Public
Metadata Only:
- Addresses involved in transactions
- Transaction occurred (event logs)
- Proposal created/voted/executed
- Pool exists
- Hooks configured
No Amounts or Quantities Revealed
Attack Resistance
Front-Running Protection
Problem: Observers see pending transactions and exploit them
FHE Solution:
- Transaction amounts encrypted
- Cannot determine trade size
- Cannot calculate price impact
- MEV bots cannot extract value
Timing Analysis
Problem: Transaction timing could leak information
Mitigation:
- Amounts encrypted regardless of timing
- No correlation between timing and amount
- Batch processing where applicable
Balance Inference
Problem: Multiple observations might infer balance
FHE Solution:
- Each observation sees only ciphertext
- Cannot correlate observations
- Balance always encrypted
- No partial information leakage
Performance Considerations
Computation Costs
FHE operations are more expensive than plaintext:
| Operation | Gas Multiplier |
|---|---|
| FHE Addition | ~10x standard |
| FHE Multiplication | ~20x standard |
| FHE Division | ~30x standard |
| FHE Comparison | ~15x standard |
Optimization Strategies:
- Minimize FHE operations
- Batch operations when possible
- Use efficient algorithms
- Cache results appropriately
Storage Costs
Encrypted values require more storage:
euint64larger thanuint64- Additional metadata for ACLs
- Proofs stored temporarily
Trade-off: Privacy costs more gas but provides confidentiality
Future Enhancements
Improved FHE Primitives
- More efficient operations
- Larger integer types
- Floating-point support
- String encryption
Advanced Privacy Features
- Range proofs (prove value in range without revealing)
- Confidential smart contracts (encrypted code)
- Private state channels (off-chain privacy)
- Cross-contract encrypted calls
Summary
Lunarys provides strong privacy guarantees through:
- Client-side encryption: Data encrypted before submission
- FHE operations: Compute without decryption
- Encrypted storage: All sensitive data stays encrypted
- Selective decryption: Only aggregate results revealed
- Oracle security: Threshold decryption prevents compromise
- Permission system: Fine-grained access control
This approach ensures that sensitive financial data remains confidential while maintaining the transparency and verifiability of blockchain technology.