Documentation Index Fetch the complete documentation index at: https://docs.privora.xyz/llms.txt
Use this file to discover all available pages before exploring further.
FHE operations require significantly more memory than typical Solana programs. Privora provides a custom allocator to handle large ciphertexts.
Why a Custom Allocator?
The Problem
Allocator Heap Size FHE Support Default Solana ~32KB No Privora FHE ~1MB Yes
FHE ciphertexts are 10-100KB each. With the default allocator, even loading two ciphertexts would exceed available memory.
The Solution
The FheBumpAllocator provides:
~1MB heap space (configurable)
Bump allocation (fast, no deallocation)
Compatible with Solana BPF environment
Setup
Basic Setup
Add at the top of your lib.rs:
use privora_sdk_program :: prelude ::* ;
// CRITICAL: Must be at crate root
privora_sdk_program :: setup_fhe_allocator! ();
Custom Heap Size
For programs needing more memory:
// 2MB heap
privora_sdk_program :: setup_fhe_allocator! ( 2 * 1024 * 1024 );
How It Works
Macro Expansion
The macro expands to:
#[cfg(target_os = "solana" )]
#[global_allocator]
static FHE_ALLOCATOR : FheBumpAllocator = FheBumpAllocator :: new ();
Key points:
Only active when compiling for Solana (target_os = "solana")
Uses #[global_allocator] to replace the default allocator
Static lifetime - exists for program duration
Bump Allocation
The allocator uses bump allocation:
Heap Start Heap End
| |
v v
+---+---+---+---+---+---+---+---+---+---+---+---+
|AAA|BBB|CCC| | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+
^
|
Next allocation here
Properties:
Fast : O(1) allocation (just bump a pointer)
No deallocation : Memory is never freed during execution
Reset on completion : All memory reclaimed when program exits
FheBumpAllocator API
Construction
use privora_sdk_program :: memory :: allocator :: FheBumpAllocator ;
// Default ~1MB heap
let allocator = FheBumpAllocator :: new ();
// Custom heap size
let allocator = FheBumpAllocator :: with_heap_size ( 2 * 1024 * 1024 );
Constants
// Default heap size (~1MB)
pub const FHE_HEAP_SIZE : usize = 1024 * 1024 - 16 ; // 1048560 bytes
// Heap start address (Solana BPF)
const HEAP_START_ADDRESS : usize = 0x300000000 ;
Memory Usage Patterns
Typical Memory Usage
Operation Memory Used Load u8 ciphertext ~10KB Load u64 ciphertext ~80KB FHE addition result ~10-80KB Comparison result ~1KB
Example Program
privora_sdk_program :: setup_fhe_allocator! ();
pub fn match_orders ( /* ... */ ) -> ProgramResult {
// Load 4 u8 ciphertexts: ~40KB
let buy_price = buy_price_ref . load () ? ; // ~10KB
let buy_qty = buy_qty_ref . load () ? ; // ~10KB
let sell_price = sell_price_ref . load () ? ; // ~10KB
let sell_qty = sell_qty_ref . load () ? ; // ~10KB
// Comparison: ~1KB
let can_match = buy_price . ge ( & sell_price ) ? ;
// Min operation: ~10KB result
let fill_qty = buy_qty . min ( & sell_qty ) ? ;
// Total: ~60KB, well within 1MB
Ok (())
}
Troubleshooting
Out of Memory Error
Error: memory allocation failed
Causes:
setup_fhe_allocator!() not called
Called in wrong location (not crate root)
Exceeded heap size
Solutions:
// Ensure allocator is at crate root, before everything else
privora_sdk_program :: setup_fhe_allocator! ();
// Then imports
use privora_sdk_program :: prelude ::* ;
// Then entrypoint
solana_program :: entrypoint! ( process_instruction );
Allocator Not Active
If FHE operations fail in tests:
// The allocator only activates for target_os = "solana"
// In tests, standard allocation is used
#[cfg(not(target_os = "solana" ))]
// Tests use system allocator - ensure FheTestEnv is set up
let mut env = FheTestEnv :: new ();
Heap Size Too Small
For complex programs with many operations:
// Increase heap size
privora_sdk_program :: setup_fhe_allocator! ( 2 * 1024 * 1024 ); // 2MB
Best Practices
1. Load Only What You Need
// Good: Load once, use multiple times
let price = price_ref . load () ? ;
let result1 = price . add ( & other1 ) ? ;
let result2 = price . add ( & other2 ) ? ;
// Avoid: Unnecessary loads
let result1 = price_ref . load () ?. add ( & other1 ) ? ;
let result2 = price_ref . load () ?. add ( & other2 ) ? ; // Extra 10KB!
2. Process in Batches
For large workloads:
// If processing many items, consider transaction batching
// Each transaction gets fresh memory
3. Use Appropriate Types
// Good: u8 for small values
let price : Encrypted < u8 > = price_ref . load () ? ; // ~10KB
// Only use u64 when needed
let large_amount : Encrypted < u64 > = amount_ref . load () ? ; // ~80KB
Memory Layout
The Solana BPF memory layout:
0x100000000 - Program text
0x200000000 - Stack
0x300000000 - Heap (FheBumpAllocator lives here)
0x400000000 - Input data
The allocator manages the heap region starting at 0x300000000.
Comparison with Default Allocator
Feature Default FheBumpAllocator Heap Size ~32KB ~1MB Allocation Bump Bump Deallocation None None FHE Support No Yes Performance Fast Fast
Next Steps
Testing Test your FHE programs
Optimization Performance optimization tips