Standard Library
The Parasol standard library provides FHE-friendly operations for writing encrypted computation programs. These functions are available by including <parasol.h> in FHE programs.
Type Definitions
The library defines standard integer types and booleans for compatibility with standard C:
bool: Boolean type (true/false)uint8_t,uint16_t,uint32_t,uint64_t: Unsigned integersint8_t,int16_t,int32_t,int64_t: Signed integers
These types can be used for both plaintext and encrypted values in FHE programs.
Conditional Selection
The select and iselect functions provide FHE-friendly conditional selection without branching. These functions return one of two values based on a boolean condition.
Basic Usage
[[clang::fhe_program]]
uint16_t apply_discount([[clang::encrypted]] uint16_t price,
[[clang::encrypted]] bool has_coupon) {
uint16_t discount_amount = 50;
uint16_t discount = select16(has_coupon, discount_amount, 0);
return price - discount;
}
This example applies a discount to a price if the user has a coupon. The select16 function returns discount_amount if has_coupon is true, otherwise returns 0.
Signed Selection with iselect
For signed integer types, use the iselect variants:
[[clang::fhe_program]]
int16_t clamp_temperature([[clang::encrypted]] int16_t temp) {
int16_t min_temp = -10;
int16_t max_temp = 40;
temp = iselect16(temp < min_temp, min_temp, temp);
temp = iselect16(temp > max_temp, max_temp, temp);
return temp;
}
This example clamps a temperature value between minimum and maximum bounds using signed selection.
Available Functions
| Function | Description |
|---|---|
select8(bool cond, uint8_t a, uint8_t b) | Returns a if cond is true, else b |
select16(bool cond, uint16_t a, uint16_t b) | Returns a if cond is true, else b |
select32(bool cond, uint32_t a, uint32_t b) | Returns a if cond is true, else b |
select64(bool cond, uint64_t a, uint64_t b) | Returns a if cond is true, else b |
iselect8(bool cond, int8_t a, int8_t b) | Signed version for int8_t |
iselect16(bool cond, int16_t a, int16_t b) | Signed version for int16_t |
iselect32(bool cond, int32_t a, int32_t b) | Signed version for int32_t |
iselect64(bool cond, int64_t a, int64_t b) | Signed version for int64_t |
Mathematical Operations
Absolute Value
[[clang::fhe_program]]
int16_t calculate_distance([[clang::encrypted]] int16_t position,
[[clang::encrypted]] int16_t target) {
int16_t difference = position - target;
return abs16(difference);
}
The absolute value functions convert negative values to positive while leaving positive values unchanged.
Available functions: abs8, abs16, abs32
Square Root
[[clang::fhe_program]]
uint8_t estimate_radius([[clang::encrypted]] uint16_t area) {
return sqrt16(area);
}
Integer square root functions compute the floor of the square root.
Available functions: sqrt8, sqrt16, sqrt32
Minimum and Maximum
[[clang::fhe_program]]
uint32_t calculate_price([[clang::encrypted]] uint32_t cost,
[[clang::encrypted]] uint32_t budget) {
uint32_t max_price = 10000;
uint32_t adjusted_budget = min32(budget, max_price);
return min32(cost, adjusted_budget);
}
These functions find the smaller or larger of two values.
Unsigned: min8, min16, min32, min64, max8, max16, max32, max64
[[clang::fhe_program]]
int16_t normalize_score([[clang::encrypted]] int16_t raw_score) {
int16_t min_score = 0;
int16_t max_score = 100;
int16_t clamped = imax16(raw_score, min_score);
return imin16(clamped, max_score);
}
Signed: imin8, imin16, imin32, imin64, imax8, imax16, imax32, imax64
Clamping
Clamp functions restrict a value to a specified range.
[[clang::fhe_program]]
uint8_t clamp_brightness([[clang::encrypted]] uint8_t brightness) {
uint8_t min_brightness = 10;
uint8_t max_brightness = 250;
return clamp8(brightness, min_brightness, max_brightness);
}
Unsigned: clamp8(uint8_t x, uint8_t min, uint8_t max) and variants for 16, 32, 64-bit
[[clang::fhe_program]]
int32_t clamp_sensor_reading([[clang::encrypted]] int32_t reading) {
int32_t min_valid = -1000;
int32_t max_valid = 1000;
return iclamp32(reading, min_valid, max_valid);
}
Signed: iclamp8(int8_t x, int8_t min, int8_t max) and variants for 16, 32, 64-bit
Sign Function
[[clang::fhe_program]]
int8_t calculate_trend([[clang::encrypted]] int32_t current,
[[clang::encrypted]] int32_t previous) {
int32_t change = current - previous;
return sign32(change);
}
The sign functions return -1 for negative values, 0 for zero, and 1 for positive values.
Available functions: sign8, sign16, sign32
Average
[[clang::fhe_program]]
uint16_t average_readings([[clang::encrypted]] uint16_t reading1,
[[clang::encrypted]] uint16_t reading2) {
return avg16(reading1, reading2);
}
Average functions compute (a + b) / 2 while avoiding overflow.
Available functions: avg8, avg16, avg32
Absolute Difference
[[clang::fhe_program]]
uint32_t compute_volatility([[clang::encrypted]] uint32_t price1,
[[clang::encrypted]] uint32_t price2) {
return absdiff32(price1, price2);
}
Computes |a - b| without overflow issues.
Unsigned: absdiff8, absdiff16, absdiff32, absdiff64
Signed: iabsdiff8, iabsdiff16, iabsdiff32
Saturating Arithmetic
Saturating arithmetic operations clamp results to the minimum or maximum representable value instead of wrapping around on overflow or underflow.
Unsigned Saturating Operations
[[clang::fhe_program]]
uint16_t add_tokens([[clang::encrypted]] uint16_t current_tokens,
[[clang::encrypted]] uint16_t bonus_tokens) {
return sadd16(current_tokens, bonus_tokens);
}
If the sum would exceed the maximum value, the result is clamped to the maximum.
[[clang::fhe_program]]
uint32_t spend_balance([[clang::encrypted]] uint32_t balance,
[[clang::encrypted]] uint32_t amount) {
return ssub32(balance, amount);
}
If the difference would go below zero, the result is clamped to 0.
Available functions: sadd8, sadd16, sadd32, ssub8, ssub16, ssub32
Signed Saturating Operations
[[clang::fhe_program]]
int16_t adjust_health([[clang::encrypted]] int16_t current_health,
[[clang::encrypted]] int16_t healing) {
return isadd16(current_health, healing);
}
[[clang::fhe_program]]
int32_t apply_damage([[clang::encrypted]] int32_t health,
[[clang::encrypted]] int32_t damage) {
return issub32(health, damage);
}
Signed saturating operations clamp to INT_MIN or INT_MAX on overflow.
Available functions: isadd8, isadd16, isadd32, isadd64, issub8, issub16, issub32, issub64
Power Functions
Power functions compute exponentiation using repeated squaring for constant circuit depth per exponent value.
[[clang::fhe_program]]
uint16_t calculate_compound_interest([[clang::encrypted]] uint16_t principal) {
uint16_t rate = 2;
uint8_t years = 5;
return principal * pow16(rate, years) / 32;
}
Unsigned: pow8, pow16, pow32, pow64 (compute base^exp for unsigned base)
[[clang::fhe_program]]
int16_t calculate_trajectory([[clang::encrypted]] int16_t velocity) {
uint8_t time = 3;
return velocity * powi16(2, time);
}
Signed: powi8, powi16, powi32, powi64 (compute base^exp for signed base)
Note: Exponents are limited to 0-15.
Conditional Swap
[[clang::fhe_program]]
uint64_t sort_two_values([[clang::encrypted]] uint32_t a,
[[clang::encrypted]] uint32_t b,
[[clang::encrypted]] uint32_t *min_out,
[[clang::encrypted]] uint32_t *max_out) {
bool swap_needed = a > b;
cswap32(swap_needed, a, b);
*min_out = a;
*max_out = b;
return (uint64_t)b - (uint64_t)a;
}
Conditional swap functions exchange two values if a condition is true. This is useful for sorting and comparison operations.
Unsigned: cswap8, cswap16, cswap32, cswap64
Signed: icswap8, icswap16, icswap32, icswap64
Bit Utility Functions
Parity Checks
[[clang::fhe_program]]
bool check_parity([[clang::encrypted]] uint32_t number) {
return is_even32(number);
}
Available functions:
- Even:
is_even8,is_even16,is_even32 - Odd:
is_odd8,is_odd16,is_odd32
Bit Extraction
[[clang::fhe_program]]
bool check_permission([[clang::encrypted]] uint32_t permission_flags,
uint8_t permission_index) {
return get_bit32(permission_flags, permission_index);
}
The get_bit functions extract individual bits from an integer value.
[[clang::fhe_program]]
uint8_t count_enabled_features([[clang::encrypted]] uint8_t feature_flags) {
uint8_t count = 0;
for (uint8_t i = 0; i < 8; i++) {
if (get_bit8(feature_flags, i)) {
count++;
}
}
return count;
}
Available functions: get_bit8, get_bit16, get_bit32
Array Operations
Array operations process multiple encrypted values efficiently using tree reduction or specialized algorithms. These operations require scratch buffers for intermediate computations.
Minimum and Maximum
[[clang::fhe_program]]
uint16_t find_min_price([[clang::encrypted]] uint16_t *prices,
uint32_t count,
uint16_t *scratch) {
return min16_array(prices, count, scratch);
}
[[clang::fhe_program]]
uint16_t find_max_price([[clang::encrypted]] uint16_t *prices,
uint32_t count,
uint16_t *scratch) {
return max16_array(prices, count, scratch);
}
The min_array and max_array functions find the minimum or maximum value in an array using tree reduction. The scratch buffer must be at least as large as the input array.
Unsigned: min8_array, min16_array, min32_array, min64_array, max8_array, max16_array, max32_array, max64_array
Signature: TYPE minN_array(const TYPE *arr, uint16_t len, TYPE *scratch)
[[clang::fhe_program]]
int32_t find_temperature_range([[clang::encrypted]] int32_t *readings,
uint32_t count,
int32_t *scratch,
[[clang::encrypted]] int32_t *min_out,
[[clang::encrypted]] int32_t *max_out) {
*min_out = imin32_array(readings, count, scratch);
*max_out = imax32_array(readings, count, scratch);
return *max_out - *min_out;
}
Signed: imin8_array, imin16_array, imin32_array, imin64_array, imax8_array, imax16_array, imax32_array, imax64_array
Signature: TYPE iminN_array(const TYPE *arr, uint16_t len, TYPE *scratch)
Sum
[[clang::fhe_program]]
uint64_t calculate_total_score([[clang::encrypted]] uint16_t *scores,
uint32_t count,
uint64_t *scratch) {
return sum16_64_array(scores, count, scratch);
}
Sum functions compute the sum of array elements using tree reduction. Function names specify both input and accumulator bit widths: sum<input>_<output>_array. Choose accumulator size based on array size and performance requirements:
- Smaller accumulators: faster FHE execution, less overflow headroom
- Larger accumulators: slower execution, safer for large arrays
The scratch buffer must be at least as large as the input array and use the accumulator type.
Unsigned variants: sum8_16_array, sum8_32_array, sum8_64_array, sum16_32_array, sum16_64_array, sum32_64_array, sum32_32_array, sum64_64_array
Signature: OUTPUT_TYPE sumIN_OUT_array(const INPUT_TYPE *arr, uint16_t len, OUTPUT_TYPE *scratch)
[[clang::fhe_program]]
int64_t calculate_net_change([[clang::encrypted]] int32_t *changes,
uint32_t count,
int64_t *scratch) {
return isum32_64_array(changes, count, scratch);
}
Signed variants: isum8_16_array, isum8_32_array, isum8_64_array, isum16_32_array, isum16_64_array, isum32_64_array, isum32_32_array, isum64_64_array
Signature: OUTPUT_TYPE isumIN_OUT_array(const INPUT_TYPE *arr, uint16_t len, OUTPUT_TYPE *scratch)
Sort
[[clang::fhe_program]]
void sort_scores([[clang::encrypted]] uint32_t *scores) {
sort_uint32_asc(scores, 8);
}
[[clang::fhe_program]]
void sort_leaderboard([[clang::encrypted]] uint32_t *scores) {
sort_uint32_desc(scores, 16);
}
The array size must be a power of 2.
Unsigned ascending: sort_uint8_asc, sort_uint16_asc, sort_uint32_asc, sort_uint64_asc
Unsigned descending: sort_uint8_desc, sort_uint16_desc, sort_uint32_desc, sort_uint64_desc
Signed ascending: sort_int8_asc, sort_int16_asc, sort_int32_asc, sort_int64_asc
Signed descending: sort_int8_desc, sort_int16_desc, sort_int32_desc, sort_int64_desc
Signature: void sort_TYPEN_DIR(TYPE *arr, uint16_t len)
Requirements:
- Array length must be a power of 2 (2, 4, 8, 16, 32, etc.)
- Sort is performed in-place