Bounded integer helpers for compiling common Concrete FHE circuits
Project description
concrete-fhe-toolkit
concrete-fhe-toolkit is an unofficial helper package for
Zama Concrete. It provides reusable circuit
builders for common bounded integer operations on encrypted Concrete inputs.
The package focuses on small, explicit, integer-only FHE circuits:
- compare two encrypted integers
- 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
The compile_* helpers compile Concrete circuits whose inputs are declared as
encrypted. For example, compile_sort(...) internally compiles with
{"x": "encrypted"}.
The make_* helpers return traceable Python functions that can be composed into
larger Concrete programs. They can also run on clear Python or NumPy values for
ordinary testing, but they are designed to be compiled into encrypted-input
Concrete circuits.
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.
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
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)
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
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.
- 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.
- Larger bounds increase table-lookup bit width and cost.
- 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 Examples
This package was derived from these Kaggle experiments:
Additional usage notebook:
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file concrete_fhe_toolkit-0.1.2.tar.gz.
File metadata
- Download URL: concrete_fhe_toolkit-0.1.2.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82229fbc72815d9a31004a39527ad2376e426196cedd057fed8d10240ed6826a
|
|
| MD5 |
533a6ca8e43018fac4d905614ef86f84
|
|
| BLAKE2b-256 |
5b4f4a8a5e0aa89461a66c5127919768c010c8a61b92af7bbcd55e16473b2aa4
|
File details
Details for the file concrete_fhe_toolkit-0.1.2-py3-none-any.whl.
File metadata
- Download URL: concrete_fhe_toolkit-0.1.2-py3-none-any.whl
- Upload date:
- Size: 11.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3622f23259dce382f422a6d9262ea2377e6870ee52a7ba8483aba5361e9be1a
|
|
| MD5 |
e8c5c98c3c28ecb99542a4926523a4ba
|
|
| BLAKE2b-256 |
e3308e58081f8ea12125c343ccd7e50fb0f295634afdb9a7e3eb2f55ca73292c
|