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.
The orderbook’s matching logic demonstrates the core FHE operations: comparison and minimum.
Matching Algorithm
A buy order matches with a sell order when buy_price >= sell_price:
Buy: 100 encrypted
Sell: 95 encrypted
↓
FHE Compare
↓
EncryptedBool (true)
The fill quantity is the minimum of both quantities:
Buy Qty: 50 encrypted
Sell Qty: 60 encrypted
↓
FHE Min
↓
50 encrypted
Step-by-Step Implementation
Step 1: Load Encrypted Data
// Load encrypted price data
msg! ( "Loading encrypted price data..." );
let buy_price = buy_order
. price_ref
. load ()
. map_err ( | _ | ProgramError :: InvalidArgument ) ? ;
let sell_price = sell_order
. price_ref
. load ()
. map_err ( | _ | ProgramError :: InvalidArgument ) ? ;
// Load encrypted quantity data
msg! ( "Loading encrypted quantity data..." );
let buy_qty = buy_order
. qty_ref
. load ()
. map_err ( | _ | ProgramError :: InvalidArgument ) ? ;
let sell_qty = sell_order
. qty_ref
. load ()
. map_err ( | _ | ProgramError :: InvalidArgument ) ? ;
The load() method fetches the ciphertext from the content-addressable store using the hash reference. This is a syscall that the Privora sequencer handles.
Step 2: Compare Prices
// Use SDK's comparison method: buy_price >= sell_price
msg! ( "Performing FHE comparison (buy_price >= sell_price)..." );
let can_match = buy_price
. ge ( & sell_price )
. map_err ( | _ | ProgramError :: InvalidArgument ) ? ;
msg! ( "FHE comparison completed" );
The comparison returns an EncryptedBool - the result is encrypted and not revealed to anyone.
Step 3: Calculate Fill Quantity
// Calculate fill quantity using SDK's min method
msg! ( "Calculating fill quantity using FHE min..." );
let fill_qty = buy_qty
. min ( & sell_qty )
. map_err ( | _ | ProgramError :: InvalidArgument ) ? ;
msg! ( "FHE min calculation completed" );
Step 4: Store Result
// Use sell price as fill price (standard orderbook matching)
let fill_price_ref = sell_order . price_ref;
// Store the computed fill_qty
msg! ( "Submitting fill quantity to data store..." );
let fill_qty_ref = fill_qty
. store ()
. map_err ( | _ | ProgramError :: InvalidArgument ) ? ;
msg! ( "Fill quantity submitted with hash" );
Available FHE Operations
Comparison Operations
Operation Method Returns Greater than or equal a.ge(&b)EncryptedBoolGreater than a.gt(&b)EncryptedBoolLess than or equal a.le(&b)EncryptedBoolLess than a.lt(&b)EncryptedBool
Min/Max Operations
Operation Method Returns Minimum a.min(&b)Encrypted<T>Maximum a.max(&b)Encrypted<T>
These operations internally use comparison and select:
// min(a, b) is equivalent to:
let is_less = a . le ( & b ) ? ;
let min = is_less . select ( & a , & b ) ? ;
Conditional Logic with select()
The select operation is the FHE equivalent of a ternary operator:
// If can_match is true, use fill_qty, else use zero
let final_qty = can_match . select ( & fill_qty , & zero ) ? ;
This could be used for more complex matching logic:
// Example: Only fill if prices cross
let can_match = buy_price . ge ( & sell_price ) ? ;
let fill_qty = buy_qty . min ( & sell_qty ) ? ;
let zero = /* encrypted zero */ ;
// final_qty = can_match ? fill_qty : 0
let final_qty = can_match . select ( & fill_qty , & zero ) ? ;
FHE operations are computationally expensive:
Operation Relative Cost Load Low (data fetch) Add/Sub/Mul Medium Comparison High Min/Max High (uses comparison) Store Low (data store)
Optimization Tips
Minimize comparisons : Each comparison is expensive. If possible, batch multiple values before comparing.
Reuse loaded values : Don’t load the same EncryptedRef multiple times. Load once and reuse.
// Good: Load once, use multiple times
let price = order . price_ref . load () ? ;
let is_above_min = price . ge ( & min_price ) ? ;
let is_below_max = price . le ( & max_price ) ? ;
// Bad: Multiple loads of same data
let is_above_min = order . price_ref . load () ?. ge ( & min_price ) ? ;
let is_below_max = order . price_ref . load () ?. le ( & max_price ) ? ; // Redundant load
Why No Conditional Execution?
You cannot conditionally execute code based on encrypted values. The comparison result is encrypted.
// This is NOT possible - can_match is encrypted!
if can_match . decrypt () { // ERROR: No decrypt in program
execute_trade ();
}
Instead, use select to compute both outcomes and pick the right one:
// Both outcomes computed, select chooses which to use
let matched_status = /* encrypted matched status */ ;
let open_status = /* encrypted open status */ ;
let new_status = can_match . select ( & matched_status , & open_status ) ? ;
Return Data
The matching function returns the fill hashes via Solana’s return data mechanism:
#[cfg(target_os = "solana" )]
{
extern "C" {
fn sol_set_return_data ( data : * const u8 , length : u64 );
}
let mut return_data = [ 0 u8 ; 64 ];
return_data [ 0 .. 32 ] . copy_from_slice ( & fill_price_ref . hash ());
return_data [ 32 .. 64 ] . copy_from_slice ( & fill_qty_ref . hash ());
unsafe {
sol_set_return_data ( return_data . as_ptr (), 64 );
}
}
This allows clients to retrieve the fill hashes from the transaction result.
Next Steps
Client Usage See how to interact with the orderbook from a client