Skip to main content

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:

  1. User encrypts data with Zama's public key (client-side)
  2. Encrypted data submitted to blockchain
  3. Smart contracts perform FHE operations on encrypted data
  4. Results remain encrypted on-chain
  5. Oracle service decrypts when explicitly requested
  6. 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 euintX types
  • 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:

  1. Generate random mask
  2. Multiply both numerator and denominator by mask
  3. Decrypt only masked denominator
  4. Divide masked numerator by decrypted masked denominator
  5. Mask cancels out, correct result obtained
  6. 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:

OperationGas 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:

  • euint64 larger than uint64
  • 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:

  1. Client-side encryption: Data encrypted before submission
  2. FHE operations: Compute without decryption
  3. Encrypted storage: All sensitive data stays encrypted
  4. Selective decryption: Only aggregate results revealed
  5. Oracle security: Threshold decryption prevents compromise
  6. Permission system: Fine-grained access control

This approach ensures that sensitive financial data remains confidential while maintaining the transparency and verifiability of blockchain technology.