Skip to main content

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 integers
  • int8_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

FunctionDescription
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