concrete-fhe-toolkit
concrete-fhe-toolkit is an unofficial helper package for
Zama Concrete. It provides reusable circuit
builders for common bounded math operations on encrypted Concrete inputs.
The package focuses on explicit, bounded FHE circuits:
- compare two encrypted integers
- add, subtract, multiply, negate, square, and compare encrypted integers
- compute encrypted integer math such as
abs, clamp, modulo, GCD, LCM,isqrt, primality, factorial, Fibonacci, combinations, and permutations - approximate fixed-point math such as floor, ceil, round, rescale,
sin,cos,log,sqrt,erf,tanh, and sigmoid with lookup tables - compare-swap two encrypted integers
- sort encrypted integer arrays
- find encrypted-array min/max values
- find encrypted-array argmin/argmax indices
- perform bounded encrypted floor division with a table lookup
- perform bounded
numerator // (left * right)
Installation
pip install concrete-fhe-toolkit
To install the latest source directly from GitHub:
pip install git+https://github.com/ErkanIsikB/concrete-fhe-toolkit.git
Or clone the repository and install it locally:
git clone https://github.com/ErkanIsikB/concrete-fhe-toolkit.git
cd concrete-fhe-toolkit
pip install .
Concrete 2.11 supports Python 3.9 through 3.12 on Linux and macOS.
Important Concept
Most users can start with the plain operation names in
concrete_fhe_toolkit.math. Calling one of these operations compiles a Concrete
circuit by default:
from concrete_fhe_toolkit import math as fhe_math
gcd = fhe_math.gcd(min_value=0, max_value=8)
print(gcd.encrypt_run_decrypt(6, 4))
# 2
These operation objects also expose the lower-level builders:
fhe_math.gcd.compile(...)compiles a ready-to-run encrypted circuit.fhe_math.gcd.make(...)returns a traceable function that can be composed into a larger Concrete program.
The explicit compile_* and make_* names remain available for advanced users
and backwards compatibility. For example, fhe_math.compile_gcd(...) is the
same compiler used by fhe_math.gcd(...), and fhe_math.make_gcd(...) is the
same builder used by fhe_math.gcd.make(...).
Use make_* only when you are manually composing several operations into one
larger circuit. For ordinary one-operation usage, prefer the plain operation
name or the explicit compile_* helper.
All operations use integer inputs. You must choose fixed input bounds when compiling a circuit, and runtime inputs must stay inside those bounds.
The bounds are not the hidden minimum and maximum of a particular encrypted
array. They are public, application-level limits that you know before
compilation. For example, if your encrypted scores are always percentages, use
min_value=0 and max_value=100. If your private balances are stored in a
range from -1_000 to 1_000, use those as the bounds. Wider bounds are more
flexible, but they usually make the compiled circuit more expensive.
The concrete_fhe_toolkit.math subpackage is intentionally closer to Python's
math module, but every operation still needs explicit bounds because FHE
circuits are compiled ahead of time. Fixed-point helpers accept encrypted
integers that represent scaled real values. For example, with
input_scale=100, the encrypted integer 314 represents 3.14.
Common bound parameters:
| Parameter style | Meaning |
|---|---|
min_value, max_value |
Inclusive input range for one or two integer inputs |
min_input, max_input |
Inclusive input range for scaled fixed-point values |
max_n |
Encrypted index range 0..max_n, used by factorial/Fibonacci/combinatorics |
numerator_width, denominator_width |
Unsigned scalar bit widths for bit-level division |
fractional_bits |
Number of binary fractional bits in fixed-point division output |
Quick Start
import numpy as np
from concrete_fhe_toolkit import compile_argmin, compile_sort
values = np.array([12, 3, 7, 1, 15, 0, 4, 9], dtype=np.int64)
sort_circuit = compile_sort(size=8, min_value=0, max_value=100)
print(sort_circuit.encrypt_run_decrypt(values))
# [ 0 1 3 4 7 9 12 15]
argmin_circuit = compile_argmin(size=8, min_value=0, max_value=100)
print(argmin_circuit.encrypt_run_decrypt(values))
# 5
Math helpers live under concrete_fhe_toolkit.math:
from concrete_fhe_toolkit import math as fhe_math
gcd_circuit = fhe_math.gcd(min_value=0, max_value=8)
print(gcd_circuit.encrypt_run_decrypt(6, 4))
# 2
sin_circuit = fhe_math.sin(
min_input=0,
max_input=90,
input_scale=1,
output_scale=100,
angle_unit="degrees",
)
print(sin_circuit.encrypt_run_decrypt(30))
# 50 (represents 0.50)
Documentation
The README is the shared GitHub and PyPI landing page. It gives the core usage model, quick examples, and the public API overview.
For the fuller guide, use the GitHub documentation:
The short version: use fhe_math.gcd(...) or another friendly operation name
for a ready-to-run circuit, use .make(...) when composing a larger Concrete
program, and choose public bounds that cover all runtime inputs.
Public API
Scalar arithmetic:
sign(x, y)compile_sign(min_value=-15, max_value=15, configuration=None)make_floor_divide(zero_result=0)compile_floor_divide(max_numerator, max_denominator, zero_result=0, configuration=None)make_floor_divide_by_product(zero_result=0)compile_floor_divide_by_product(max_numerator, max_left, max_right, zero_result=0, configuration=None)
Array operations:
make_compare_swap(min_value=0, max_value=15)compile_compare_swap(min_value=0, max_value=15, configuration=None)make_sort(size, min_value=0, max_value=15, descending=False)compile_sort(size, min_value=0, max_value=15, descending=False, configuration=None)make_minimum(size, min_value=0, max_value=15)compile_minimum(size, min_value=0, max_value=15, configuration=None)make_maximum(size, min_value=0, max_value=15)compile_maximum(size, min_value=0, max_value=15, configuration=None)make_argmin(size, min_value=0, max_value=15, tie_break="first")compile_argmin(size, min_value=0, max_value=15, tie_break="first", configuration=None)make_argmax(size, min_value=0, max_value=15, tie_break="first")compile_argmax(size, min_value=0, max_value=15, tie_break="first", configuration=None)
Math subpackage:
from concrete_fhe_toolkit import math as fhe_math
Friendly operation objects compile by default and expose .make(...) and
.compile(...) for explicit control:
absolute,clamp,modulo,divmod,is_closefactorial,fibonacci,power,comb,permgcd,lcm,is_coprime,is_divisible,isqrt,is_even,is_odd,is_primefloor,ceil,trunc,round,floor_ceil,rescalesin,cos,tan,exp,expm1,log,log1p,log2,log10,sqrt,erf,erfc,tanh,sinh,cosh,sigmoidunsigned_floor_divide,fixed_point_divide
Basic integer operations:
- native arithmetic:
add,subtract,multiply,negate,square - comparisons:
equal,not_equal,less,less_equal,greater,greater_equal - compilers:
compile_add,compile_subtract,compile_multiply,compile_negate,compile_square,compile_scalar_multiply - lookup helpers:
make_absolute,compile_absolute,make_clamp,compile_clamp,make_modulo,compile_modulo,make_divmod,compile_divmod,make_is_close,compile_is_close
Combinatorics:
make_factorial,compile_factorialmake_fibonacci,compile_fibonaccimake_power,compile_powermake_comb,compile_combmake_perm,compile_perm
Number theory:
make_gcd,compile_gcdmake_lcm,compile_lcmmake_is_coprime,compile_is_coprimemake_is_divisible,compile_is_divisiblemake_isqrt,compile_isqrtmake_is_even,compile_is_evenmake_is_odd,compile_is_oddmake_is_prime,compile_is_prime
Fixed-point helpers:
make_floor,compile_floormake_ceil,compile_ceilmake_trunc,compile_truncmake_round,compile_roundmake_floor_ceil,compile_floor_ceilmake_rescale,compile_rescale
Special fixed-point helpers:
- trigonometric:
make_sin,compile_sin,make_cos,compile_cos,make_tan,compile_tan - exponential/logarithmic:
make_exp,compile_exp,make_expm1,compile_expm1,make_log,compile_log,make_log1p,compile_log1p,make_log2,compile_log2,make_log10,compile_log10 - roots/special activations:
make_sqrt,compile_sqrt,make_erf,compile_erf,make_erfc,compile_erfc,make_tanh,compile_tanh,make_sinh,compile_sinh,make_cosh,compile_cosh,make_sigmoid,compile_sigmoid
Bit-level arithmetic helpers:
- bit primitives:
bit_not,bit_and,bit_or,bit_xor,bit_select,full_adder_bit,full_subtractor_bit - conversion helpers:
integer_to_bits,bits_to_unsigned,unsigned_to_bits,twos_complement_bits - signed bit helpers:
sign_magnitude_to_twos_complement_bits,twos_complement_add_bits,twos_complement_multiply_by_constant_bits - binary division:
unsigned_divide_bits,fixed_point_divide_bits,make_unsigned_floor_divide,compile_unsigned_floor_divide,make_fixed_point_divide,compile_fixed_point_divide
Examples
Sign Comparison
compile_sign returns 1 when x > y, 0 when x == y, and -1 when
x < y.
from concrete_fhe_toolkit import compile_sign
circuit = compile_sign(min_value=-20, max_value=20)
print(circuit.encrypt_run_decrypt(15, 3))
# 1
print(circuit.encrypt_run_decrypt(3, 15))
# -1
print(circuit.encrypt_run_decrypt(7, 7))
# 0
Compare-Swap
compile_compare_swap returns two values in ascending order.
from concrete_fhe_toolkit import compile_compare_swap
circuit = compile_compare_swap(min_value=0, max_value=100)
print(circuit.encrypt_run_decrypt(12, 3))
# (3, 12)
Sort
compile_sort sorts a fixed-size encrypted array. The size must be a power of
two.
import numpy as np
from concrete_fhe_toolkit import compile_sort
values = np.array([12, 3, 7, 1, 15, 0, 4, 9], dtype=np.int64)
ascending = compile_sort(size=8, min_value=0, max_value=100)
print(ascending.encrypt_run_decrypt(values))
# [ 0 1 3 4 7 9 12 15]
descending = compile_sort(size=8, min_value=0, max_value=100, descending=True)
print(descending.encrypt_run_decrypt(values))
# [15 12 9 7 4 3 1 0]
Minimum and Maximum
compile_minimum and compile_maximum return the smallest or largest value in
a fixed-size encrypted array.
import numpy as np
from concrete_fhe_toolkit import compile_maximum, compile_minimum
values = np.array([12, 5, 7, 2, 15, 9, 4, 14], dtype=np.int64)
minimum = compile_minimum(size=8, min_value=0, max_value=100)
print(minimum.encrypt_run_decrypt(values))
# 2
maximum = compile_maximum(size=8, min_value=0, max_value=100)
print(maximum.encrypt_run_decrypt(values))
# 15
Argmin and Argmax
compile_argmin and compile_argmax return the index of the smallest or
largest value. By default, ties return the first matching index.
import numpy as np
from concrete_fhe_toolkit import compile_argmax, compile_argmin
values = np.array([12, 5, 7, 1, 15, 9, 4, 14], dtype=np.int64)
argmin = compile_argmin(size=8, min_value=0, max_value=100)
print(argmin.encrypt_run_decrypt(values))
# 3
argmax = compile_argmax(size=8, min_value=0, max_value=100)
print(argmax.encrypt_run_decrypt(values))
# 4
Tie handling is explicit:
import numpy as np
from concrete_fhe_toolkit import compile_argmin
values = np.array([4, 1, 1, 3], dtype=np.int64)
first = compile_argmin(size=4, min_value=0, max_value=10, tie_break="first")
print(first.encrypt_run_decrypt(values))
# 1
last = compile_argmin(size=4, min_value=0, max_value=10, tie_break="last")
print(last.encrypt_run_decrypt(values))
# 2
Floor Division
Direct x // y does not compile when both values are encrypted in Concrete
2.11. This package implements bounded floor division with
fhe.multivariate.
from concrete_fhe_toolkit import compile_floor_divide
circuit = compile_floor_divide(
max_numerator=100,
max_denominator=10,
zero_result=-1,
)
print(circuit.encrypt_run_decrypt(15, 3))
# 5
print(circuit.encrypt_run_decrypt(15, 0))
# -1
zero_result is returned when the encrypted denominator is zero.
Division by an Encrypted Product
compile_floor_divide_by_product computes
numerator // (left * right).
from concrete_fhe_toolkit import compile_floor_divide_by_product
circuit = compile_floor_divide_by_product(
max_numerator=100,
max_left=10,
max_right=10,
zero_result=-1,
)
print(circuit.encrypt_run_decrypt(20, 2, 5))
# 2
print(circuit.encrypt_run_decrypt(20, 0, 5))
# -1
Math Subpackage
Use concrete_fhe_toolkit.math for Python-math-style helpers. Some compile to
native Concrete arithmetic, while functions such as GCD, factorial, prime
testing, and fixed-point sin use lookup tables over the declared domain.
from concrete_fhe_toolkit import math as fhe_math
factorial = fhe_math.factorial(max_n=7)
print(factorial.encrypt_run_decrypt(5))
# 120
modulo = fhe_math.modulo(
min_numerator=0,
max_numerator=20,
min_denominator=0,
max_denominator=10,
zero_result=-1,
)
print(modulo.encrypt_run_decrypt(17, 5))
# 2
tanh = fhe_math.tanh(
min_input=-30,
max_input=30,
input_scale=10,
output_scale=100,
)
print(tanh.encrypt_run_decrypt(20))
# 96 (represents tanh(2.0) ~= 0.96)
The plain operation name compiles by default. If you want to be explicit, use
.compile(...):
from concrete_fhe_toolkit import math as fhe_math
gcd = fhe_math.gcd.compile(min_value=0, max_value=8)
print(gcd.simulate(6, 4))
# 2
Use .make(...) when composing a larger circuit yourself:
from concrete import fhe
from concrete_fhe_toolkit import math as fhe_math
absolute = fhe_math.absolute.make(-8, 8)
gcd = fhe_math.gcd.make(0, 8)
def program(x, y):
return gcd(absolute(x), y)
compiler = fhe.Compiler(program, {"x": "encrypted", "y": "encrypted"})
circuit = compiler.compile([(x, y) for x in range(-8, 9) for y in range(9)])
print(circuit.encrypt_run_decrypt(-6, 4))
# 2
Functions with undefined mathematical inputs require an explicit encrypted fallback if the compiled domain includes invalid values:
from concrete_fhe_toolkit import math as fhe_math
log2 = fhe_math.log2(
min_input=0,
max_input=16,
invalid_result=-1,
)
print(log2.encrypt_run_decrypt(0))
# -1
Large lookup tables are available, but the package asks you to opt in when a static estimate suggests the circuit may need substantial Concrete resources:
from concrete_fhe_toolkit import math as fhe_math
gcd = fhe_math.gcd(
min_value=0,
max_value=31,
allow_large_lookup=True,
)
print(gcd.simulate(24, 18))
# 6
Bit-Level Fixed-Point Division
unsigned_floor_divide and fixed_point_divide use a restoring binary
division circuit instead of a full lookup table. They are useful when you want
division logic that scales with bit width rather than with every possible
(numerator, denominator) value.
from concrete_fhe_toolkit import math as fhe_math
floor_divide = fhe_math.unsigned_floor_divide(
numerator_width=8,
denominator_width=8,
zero_result=0,
)
print(floor_divide.encrypt_run_decrypt(100, 7))
# 14
fixed_divide = fhe_math.fixed_point_divide(
numerator_width=8,
denominator_width=8,
fractional_bits=8,
)
print(fixed_divide.encrypt_run_decrypt(1, 3))
# 85 (represents floor((1 / 3) * 256))
Inputs for these helpers must be unsigned integers that fit in the declared bit
widths. Division by zero returns zero_result.
Composing make_* Helpers
Use make_* helpers when you want to build a larger Concrete function yourself.
When compiling manually, your inputset must cover the bounds you declared.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit import make_minimum
minimum_of_four = make_minimum(size=4, min_value=0, max_value=100)
compiler = fhe.Compiler(minimum_of_four, {"x": "encrypted"})
inputset = [
np.array([0, 0, 0, 0], dtype=np.int64),
np.array([100, 100, 100, 100], dtype=np.int64),
np.array([0, 100, 0, 100], dtype=np.int64),
np.array([100, 0, 100, 0], dtype=np.int64),
]
circuit = compiler.compile(inputset)
print(circuit.encrypt_run_decrypt(np.array([8, 3, 12, 5], dtype=np.int64)))
# 3
For most use cases, prefer the compile_* helpers because they generate
boundary-aware inputsets automatically.
Bounds and Limitations
- Inputs must stay inside the bounds used at compilation.
- Plain
concrete_fhe_toolkit.mathoperation names compile by default. Use.make(...)only when composing larger circuits manually. - Sorting requires a power-of-two array size.
- Min/max and argmin/argmax support any positive fixed size.
- Division helpers currently support nonnegative bounded inputs.
- Bit-level division helpers support unsigned scalar inputs that fit in the declared bit widths and return integer or scaled-integer outputs.
- Larger bounds increase table-lookup bit width and cost. Some math helpers
raise
LookupResourceErrorunless you passallow_large_lookup=True. concrete_fhe_toolkit.mathfixed-point helpers return scaled integers, not Python floats.- Lookup-table outputs that require very large integer bit widths may exceed Concrete's available parameter set even if you opt in to large lookups.
- Concrete supports integer inputs and outputs, not arbitrary floating point.
- FHE execution is probabilistic; choose Concrete error parameters appropriate for the application's risk.
Notebook provenance and examples
This package was derived from these Kaggle experiments:
Additional usage notebook:
The notebooks are useful background and examples, but the README and
docs/
are the canonical documentation for the current package API. Existing
make_* and compile_* package APIs were kept for compatibility, while the
new concrete_fhe_toolkit.math friendly operation names provide the preferred
high-level interface for new code.
License and Concrete Terms
The package's original code is available under the MIT License. MIT permits commercial and private use, modification, and redistribution while requiring the copyright and license notice to be preserved.
Concrete is a separate dependency with its own BSD-3-Clause-Clear license and patent terms. This package does not change or grant rights under Concrete's license. Review Zama's current licensing terms before commercial use.
This project is not affiliated with or endorsed by Zama.
Author and Contributors
Author and maintainer
- Erkan Işık Bacak
Contributors
- Tolga Büyüktanır
- Didem Civelek
- Yusuf Emir Alakuş
Organizational contributor
Metadata
Release files for concrete-fhe-toolkit 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| concrete_fhe_toolkit-0.2.1.tar.gz | 47.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| concrete_fhe_toolkit-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 79.9 kB
Release files / concrete_fhe_toolkit-0.2.1.tar.gz
| Download URL | concrete_fhe_toolkit-0.2.1.tar.gz |
|---|---|
| Size | 47.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0ef1e21c4a36d1eca99a43422047607d8f01533ee91351163fff3fafb3bde65b
|
|
BLAKE2b-256 checksum How to use checksums |
5283d1c6167d87e0ce628e4e4569f0f72095229b6afa742b886bef3034a1f63b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.12
|
Release files / concrete_fhe_toolkit-0.2.1-py3-none-any.whl
| Download URL | concrete_fhe_toolkit-0.2.1-py3-none-any.whl |
|---|---|
| Size | 32.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
868795c1bc69721d5bebde68c435a85f5f66f97e1508dcb0efbee5d2d622b0f5
|
|
BLAKE2b-256 checksum How to use checksums |
77a64bf47ddaedf889abf16f8388746e153e41b77ae7125e93ca45882200a0e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.12
|