Skip to main content

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

Metadata

Release files for concrete-fhe-toolkit 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for concrete-fhe-toolkit 0.1.3
File Size Uploaded
concrete_fhe_toolkit-0.1.3.tar.gz 15.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for concrete-fhe-toolkit 0.1.3
File Interpreter ABI Platform
concrete_fhe_toolkit-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 26.8 kB

Release files / concrete_fhe_toolkit-0.1.3.tar.gz

Download URL concrete_fhe_toolkit-0.1.3.tar.gz
Size 15.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b2d8428134a87696ee5200fb009a23d6fe76794bda2d9a22b1e9ba4b16f84fa7
BLAKE2b-256 checksum
How to use checksums
a6e50422e9d7a88520d28cff50fac12bdde456406dea4d5ae554f21458533716
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.1.3-py3-none-any.whl

Download URL concrete_fhe_toolkit-0.1.3-py3-none-any.whl
Size 11.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7dac9151a01f35d2680f02fdb11c1dec6653f94e342eec634e6879feaca70807
BLAKE2b-256 checksum
How to use checksums
5b5fe80807138e7df1288273a3462a190d819d1bd530a363124a2d157a76db63
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page