Arrays¶
This notebook tests and demonstrates the encrypted array primitives in the toolkit.
array_sum()¶
Calculates the sum of an encrypted array. Tests positive, negative, zero, and alternating arrays.
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_sum
def test_array_sum(arr):
return array_sum(arr)
compiler = fhe.Compiler(test_array_sum, {"arr": "encrypted"})
inputset = [([5, 5, 5, 5],), ([0, 0, 0, 0],), ([-5, 5, -5, 5],), ([-2, -3, -4, -1],)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([5, 5, 5, 5]) == 20
assert circuit.encrypt_run_decrypt([0, 0, 0, 0]) == 0
assert circuit.encrypt_run_decrypt([-5, 5, -5, 5]) == 0
assert circuit.encrypt_run_decrypt([-2, -3, -4, -1]) == -10
print("array_sum tests passed!")
array_scale()¶
Multiplies an array by a scalar. Tests zero scale, negative scale, and positive scale.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_scale
def test_array_scale(arr, factor):
return array_scale(arr, factor)
compiler = fhe.Compiler(test_array_scale, {"arr": "encrypted", "factor": "clear"})
inputset = [([1, 2, 3], 3), ([0, 0, 0], 5), ([-1, 2, -3], -2), ([5, 10, 15], 0)]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([1, 2, 3], 3), [3, 6, 9])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0, 0], 5), [0, 0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-1, 2, -3], -2), [2, -4, 6])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, 10, 15], 0), [0, 0, 0])
print("array_scale tests passed!")
array_add()¶
Element-wise addition. Tests normal addition, negative addition, and adding zeros.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_add
def test_array_add(a1, a2):
return array_add(a1, a2)
compiler = fhe.Compiler(test_array_add, {"a1": "encrypted", "a2": "encrypted"})
inputset = [([5, 10], [10, 5]), ([-5, -10], [5, 10]), ([0, 0], [0, 0]), ([5, 5], [-5, -5])]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, 10], [10, 5]), [15, 15])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-5, -10], [5, 10]), [0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0], [0, 0]), [0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, 5], [-5, -5]), [0, 0])
print("array_add tests passed!")
array_sub()¶
Element-wise subtraction. Tests identical arrays, negative results, and zero arrays.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_sub
def test_array_sub(a1, a2):
return array_sub(a1, a2)
compiler = fhe.Compiler(test_array_sub, {"a1": "encrypted", "a2": "encrypted"})
inputset = [([15, 15], [5, 10]), ([5, 10], [15, 20]), ([0, 0], [0, 0]), ([5, 10], [5, 10]), ([-5, -5], [5, 5])]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([15, 15], [5, 10]), [10, 5])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, 10], [15, 20]), [-10, -10])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0], [0, 0]), [0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, 10], [5, 10]), [0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-5, -5], [5, 5]), [-10, -10])
print("array_sub tests passed!")
array_multiply()¶
Element-wise multiplication. Tests zeros, negatives, and normal positive cases.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_multiply
def test_array_multiply(a1, a2):
return array_multiply(a1, a2)
compiler = fhe.Compiler(test_array_multiply, {"a1": "encrypted", "a2": "encrypted"})
inputset = [([2, 3], [4, 5]), ([0, 5], [10, 0]), ([-2, -3], [4, -5])]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([2, 3], [4, 5]), [8, 15])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 5], [10, 0]), [0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-2, -3], [4, -5]), [-8, 15])
print("array_multiply tests passed!")
make_array_pad()¶
Creates a fixed-size padding function. Tests padding from smaller to target size, and exact size (no-op).
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_array_pad
pad_fn = make_array_pad(size=2, target_size=4, min_value=-15, max_value=15)
def test_pad_from_2_to_4(arr):
return pad_fn(arr)
compiler2 = fhe.Compiler(test_pad_from_2_to_4, {"arr": "encrypted"})
circuit2 = compiler2.compile([([1, 2],), ([-1, -1],)])
# make_array_pad(size=5, target_size=4, ...) will raise ValueError at creation time
pad_fn_exact = make_array_pad(size=4, target_size=4, min_value=-15, max_value=15)
def test_pad_from_4_to_4(arr):
return pad_fn_exact(arr)
compiler4 = fhe.Compiler(test_pad_from_4_to_4, {"arr": "encrypted"})
circuit4 = compiler4.compile([([1, 2, 3, 4],), ([0, 0, 0, 0],)])
np.testing.assert_array_equal(circuit2.encrypt_run_decrypt([1, 2]), [1, 2, 0, 0])
np.testing.assert_array_equal(circuit4.encrypt_run_decrypt([1, 2, 3, 4]), [1, 2, 3, 4])
print("make_array_pad tests passed!")
compile_array_pad()¶
Returns a compiled array padding circuit.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_array_pad
circuit = compile_array_pad(size=2, target_size=4, min_value=-5, max_value=5)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([1, 2]), [1, 2, 0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-3, 5]), [-3, 5, 0, 0])
print("compile_array_pad tests passed!")
array_slice()¶
Slices an array. Tests standard slice, full slice, and negative index slice (safely constrained by python slice semantics).
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_slice
def test_array_slice_1_3(arr):
return array_slice(arr, 1, 3)
def test_array_slice_all(arr):
return array_slice(arr, 0, 4)
def test_array_slice_negative(arr):
return array_slice(arr, -3, -1)
compiler1 = fhe.Compiler(test_array_slice_1_3, {"arr": "encrypted"})
circuit1 = compiler1.compile([([10, 20, 30, 40],), ([0, 0, 0, 0],)])
compiler2 = fhe.Compiler(test_array_slice_all, {"arr": "encrypted"})
circuit2 = compiler2.compile([([10, 20, 30, 40],), ([0, 0, 0, 0],)])
compiler3 = fhe.Compiler(test_array_slice_negative, {"arr": "encrypted"})
circuit3 = compiler3.compile([([10, 20, 30, 40],), ([0, 0, 0, 0],)])
np.testing.assert_array_equal(circuit1.encrypt_run_decrypt([10, 20, 30, 40]), [20, 30])
np.testing.assert_array_equal(circuit2.encrypt_run_decrypt([10, 20, 30, 40]), [10, 20, 30, 40])
np.testing.assert_array_equal(circuit3.encrypt_run_decrypt([10, 20, 30, 40]), [20, 30])
print("array_slice tests passed!")
make_array_contains()¶
Creates a membership-test function. Tests exists, does not exist, exists multiple times, negatives, zeroes.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_array_contains
contains_fn = make_array_contains(size=3, min_value=-5, max_value=5)
def test_array_contains(arr, val):
return contains_fn(arr, val)
compiler = fhe.Compiler(test_array_contains, {"arr": "encrypted", "val": "encrypted"})
inputset = [([1, 3, 5], 3), ([1, 3, 5], 2), ([0, 0, 0], 0), ([-2, -2, -2], -2), ([-1, 1, 2], -1)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([1, 3, 5], 3) == 1
assert circuit.encrypt_run_decrypt([1, 3, 5], 2) == 0
assert circuit.encrypt_run_decrypt([0, 0, 0], 0) == 1
assert circuit.encrypt_run_decrypt([-2, -2, -2], -2) == 1
assert circuit.encrypt_run_decrypt([-1, 1, 2], -1) == 1
print("make_array_contains tests passed!")
compile_array_contains()¶
Returns a compiled membership-test circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_array_contains
circuit = compile_array_contains(size=3, min_value=-5, max_value=5)
assert circuit.encrypt_run_decrypt([1, 3, 5], 3) == 1
assert circuit.encrypt_run_decrypt([1, 3, 5], 2) == 0
print("compile_array_contains tests passed!")
make_array_count()¶
Creates a value-counting function. Tests zero count, single count, multiple count, negatives and zeroes.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_array_count
count_fn = make_array_count(size=4, min_value=-8, max_value=5)
def test_array_count(arr, val):
return count_fn(arr, val)
compiler = fhe.Compiler(test_array_count, {"arr": "encrypted", "val": "encrypted"})
inputset = [([1, 2, 2, 3], 2), ([1, 2, 2, 3], 5), ([0, 0, 0, 0], 0), ([-5, -6, -5, -8], -5)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([1, 2, 2, 3], 2) == 2
assert circuit.encrypt_run_decrypt([1, 2, 2, 3], 5) == 0
assert circuit.encrypt_run_decrypt([0, 0, 0, 0], 0) == 4
assert circuit.encrypt_run_decrypt([-5, -6, -5, -8], -5) == 2
print("make_array_count tests passed!")
compile_array_count()¶
Returns a compiled value-counting circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_array_count
circuit = compile_array_count(size=4, min_value=-8, max_value=5)
assert circuit.encrypt_run_decrypt([1, 2, 2, 3], 2) == 2
assert circuit.encrypt_run_decrypt([0, 0, 0, 0], 0) == 4
print("compile_array_count tests passed!")
array_all_equal()¶
Checks if two arrays are identical. Tests identical, mismatch at start, mismatch at end, completely different, negatives.
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_all_equal
def test_array_all_equal(a1, a2):
return array_all_equal(a1, a2)
compiler = fhe.Compiler(test_array_all_equal, {"a1": "encrypted", "a2": "encrypted"})
inputset = [([1, 2, 3], [1, 2, 3]), ([1, 2, 3], [9, 2, 3]), ([1, 2, 3], [1, 2, 9]), ([0, 0, 0], [1, 1, 1]), ([-1, -2, -3], [-1, -2, -3])]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([1, 2, 3], [1, 2, 3]) == 1
assert circuit.encrypt_run_decrypt([1, 2, 3], [9, 2, 3]) == 0
assert circuit.encrypt_run_decrypt([1, 2, 3], [1, 2, 9]) == 0
assert circuit.encrypt_run_decrypt([0, 0, 0], [1, 1, 1]) == 0
assert circuit.encrypt_run_decrypt([-1, -2, -3], [-1, -2, -3]) == 1
print("array_all_equal tests passed!")
make_compare_swap()¶
Creates ascending compare-swap. Tests x > y, x < y, x == y, zeroes and negative inputs.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_compare_swap
swap = make_compare_swap(min_value=-15, max_value=15)
def test_swap(x, y):
return swap(x, y)
compiler = fhe.Compiler(test_swap, {"x": "encrypted", "y": "encrypted"})
inputset = [(5, 3), (2, 4), (7, 7), (-5, -10), (0, 0), (-2, 5)]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(5, 3), [3, 5])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(2, 4), [2, 4])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(7, 7), [7, 7])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(-5, -10), [-10, -5])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(0, 0), [0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(-2, 5), [-2, 5])
print("make_compare_swap tests passed!")
make_sort()¶
Creates a bitonic sorting network. Tests reverse sorted, already sorted, duplicates, zeroes and negatives.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_sort
sort_fn = make_sort(size=4, min_value=-15, max_value=15)
def test_sort(x):
return sort_fn(x)
compiler = fhe.Compiler(test_sort, {"x": "encrypted"})
inputset = [([4, 3, 2, 1],), ([1, 2, 3, 4],), ([5, 5, 5, 5],), ([0, -5, -2, 3],), ([0, 0, 0, 0],), ([-5, -5, -5, -5],)]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([4, 3, 2, 1]), [1, 2, 3, 4])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([1, 2, 3, 4]), [1, 2, 3, 4])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, 5, 5, 5]), [5, 5, 5, 5])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, -5, -2, 3]), [-5, -2, 0, 3])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0, 0, 0]), [0, 0, 0, 0])
print("make_sort tests passed!")
make_minimum()¶
Creates a minimum reduction function. Tests min at start, min at end, duplicates, zeroes and negatives.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_minimum
min_fn = make_minimum(size=4, min_value=-15, max_value=15)
def test_min(x):
return min_fn(x)
compiler = fhe.Compiler(test_min, {"x": "encrypted"})
inputset = [([1, 4, 3, 2],), ([5, 5, 5, 5],), ([8, 9, 3, 0],), ([-1, -5, -2, -3],), ([0, 0, 0, 0],)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([1, 4, 3, 2]) == 1
assert circuit.encrypt_run_decrypt([5, 5, 5, 5]) == 5
assert circuit.encrypt_run_decrypt([8, 9, 3, 0]) == 0
assert circuit.encrypt_run_decrypt([-1, -5, -2, -3]) == -5
assert circuit.encrypt_run_decrypt([0, 0, 0, 0]) == 0
print("make_minimum tests passed!")
make_maximum()¶
Creates a maximum reduction function. Tests max at start, max at end, duplicates, zeroes and negatives.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_maximum
max_fn = make_maximum(size=4, min_value=-15, max_value=15)
def test_max(x):
return max_fn(x)
compiler = fhe.Compiler(test_max, {"x": "encrypted"})
inputset = [([4, 1, 3, 2],), ([5, 5, 5, 5],), ([0, 8, 3, 9],), ([-1, -5, -2, -3],), ([0, 0, 0, 0],)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([4, 1, 3, 2]) == 4
assert circuit.encrypt_run_decrypt([5, 5, 5, 5]) == 5
inputset = [([4, 1, 3, 2],), ([5, 5, 5, 5],), ([0, 4, 3, 5],), ([-1, -5, -2, -3],), ([0, 0, 0, 0],)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([4, 1, 3, 2]) == 4
assert circuit.encrypt_run_decrypt([5, 5, 5, 5]) == 5
assert circuit.encrypt_run_decrypt([0, 4, 3, 5]) == 5
assert circuit.encrypt_run_decrypt([-1, -5, -2, -3]) == -1
assert circuit.encrypt_run_decrypt([0, 0, 0, 0]) == 0
print("make_maximum tests passed!")
make_argmin()¶
Creates an argmin reduction. Tests argmin at start, at end, with duplicates (returns first index) and negatives.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_argmin
argmin_fn = make_argmin(size=4, min_value=-5, max_value=5)
def test_argmin(x):
return argmin_fn(x)
compiler = fhe.Compiler(test_argmin, {"x": "encrypted"})
inputset = [([1, 4, 3, 2],), ([4, 1, 1, 2],), ([5, 4, 3, 0],), ([-5, -1, -2, -3],), ([5, 5, 5, 5],), ([-5, -5, -5, -5],)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([1, 4, 3, 2]) == 0
assert circuit.encrypt_run_decrypt([4, 1, 1, 2]) == 1
assert circuit.encrypt_run_decrypt([5, 4, 3, 0]) == 3
assert circuit.encrypt_run_decrypt([-5, -1, -2, -3]) == 0
print("make_argmin tests passed!")
make_argmax()¶
Creates an argmax reduction. Tests argmax at start, at end, with duplicates (returns first index) and negatives.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_argmax
argmax_fn = make_argmax(size=4, min_value=-5, max_value=5)
def test_argmax(x):
return argmax_fn(x)
compiler = fhe.Compiler(test_argmax, {"x": "encrypted"})
inputset = [([5, 1, 3, 2],), ([4, 5, 5, 2],), ([0, 1, 2, 5],), ([-5, -1, -2, -3],), ([5, 5, 5, 5],), ([-5, -5, -5, -5],)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([5, 1, 3, 2]) == 0
assert circuit.encrypt_run_decrypt([4, 5, 5, 2]) == 1
assert circuit.encrypt_run_decrypt([0, 1, 2, 5]) == 3
assert circuit.encrypt_run_decrypt([-5, -1, -2, -3]) == 1
print("make_argmax tests passed!")
compile_compare_swap()¶
Returns a compiled compare-swap circuit.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_compare_swap
circuit = compile_compare_swap(min_value=-5, max_value=5)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(5, 3), [3, 5])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt(1, 4), [1, 4])
print("compile_compare_swap tests passed!")
compile_sort()¶
Returns a compiled bitonic sort circuit.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_sort
circuit = compile_sort(size=4, min_value=-5, max_value=5)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([4, 1, 3, 2]), [1, 2, 3, 4])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-5, 0, 5, -4]), [-5, -4, 0, 5])
print("compile_sort tests passed!")
compile_minimum()¶
Returns a compiled minimum reduction circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_minimum
circuit = compile_minimum(size=4, min_value=-5, max_value=5)
assert circuit.encrypt_run_decrypt([4, 1, 3, 2]) == 1
assert circuit.encrypt_run_decrypt([5, 4, 3, 2]) == 2
print("compile_minimum tests passed!")
compile_maximum()¶
Returns a compiled maximum reduction circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_maximum
circuit = compile_maximum(size=4, min_value=-5, max_value=5)
assert circuit.encrypt_run_decrypt([4, 1, 3, 2]) == 4
assert circuit.encrypt_run_decrypt([1, 2, 0, 0]) == 2
print("compile_maximum tests passed!")
compile_argmin()¶
Returns a compiled argmin circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_argmin
circuit = compile_argmin(size=4, min_value=-5, max_value=5)
assert circuit.encrypt_run_decrypt([4, 1, 3, 2]) == 1
assert circuit.encrypt_run_decrypt([5, 3, 3, 4]) == 1
print("compile_argmin tests passed!")
compile_argmax()¶
Returns a compiled argmax circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_argmax
circuit = compile_argmax(size=4, min_value=-5, max_value=5)
assert circuit.encrypt_run_decrypt([4, 1, 3, 2]) == 0
assert circuit.encrypt_run_decrypt([1, 5, 5, 2]) == 1
print("compile_argmax tests passed!")
make_array_index()¶
Creates an oblivious-read function. Tests reading from start, middle, and end of the array.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_array_index
index_fn = make_array_index(size=3, min_value=0, max_value=30)
def test_array_index(arr, idx):
return index_fn(arr, idx)
compiler = fhe.Compiler(test_array_index, {"arr": "encrypted", "idx": "encrypted"})
inputset = [([10, 20, 30], 1), ([10, 20, 30], 0), ([5, 5, 5], 2)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([10, 20, 30], 1) == 20
assert circuit.encrypt_run_decrypt([10, 20, 30], 0) == 10
assert circuit.encrypt_run_decrypt([10, 20, 30], 2) == 30
print("make_array_index tests passed!")
compile_array_index()¶
Returns a compiled oblivious-read circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_array_index
circuit = compile_array_index(size=3, min_value=0, max_value=30)
assert circuit.encrypt_run_decrypt([10, 20, 30], 1) == 20
assert circuit.encrypt_run_decrypt([10, 20, 30], 0) == 10
print("compile_array_index tests passed!")
make_array_set()¶
Creates an oblivious-write function. Tests writing to start, middle, and end of the array with positive, zeroes, negatives.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_array_set
set_fn = make_array_set(size=3, min_value=-5, max_value=30)
def test_array_set(arr, idx, val):
return set_fn(arr, idx, val)
compiler = fhe.Compiler(test_array_set, {"arr": "encrypted", "idx": "encrypted", "val": "encrypted"})
inputset = [([10, 20, 30], 1, 15), ([10, 20, 30], 0, -5), ([10, 20, 30], 2, 0)]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([10, 20, 30], 1, 15), [10, 15, 30])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([10, 20, 30], 0, -5), [-5, 20, 30])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([10, 20, 30], 2, 0), [10, 20, 0])
print("make_array_set tests passed!")
compile_array_set()¶
Returns a compiled oblivious-write circuit.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_array_set
circuit = compile_array_set(size=3, min_value=-5, max_value=30)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([10, 20, 30], 1, 15), [10, 15, 30])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([10, 20, 30], 0, -5), [-5, 20, 30])
print("compile_array_set tests passed!")
make_array_index_of()¶
Creates a first-index-of search function. Tests existing element, missing element (returns size as default), first occurrence of duplicates, and zeroes.
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_array_index_of
index_of_fn = make_array_index_of(size=4, min_value=0, max_value=40)
def test_array_index_of(arr, val):
return index_of_fn(arr, val)
compiler = fhe.Compiler(test_array_index_of, {"arr": "encrypted", "val": "encrypted"})
inputset = [([10, 20, 30, 20], 20), ([10, 20, 30, 20], 40), ([10, 20, 30, 20], 30), ([0, 0, 0, 0], 0)]
circuit = compiler.compile(inputset)
assert circuit.encrypt_run_decrypt([10, 20, 30, 20], 20) == 1
assert circuit.encrypt_run_decrypt([10, 20, 30, 20], 40) == 4
assert circuit.encrypt_run_decrypt([10, 20, 30, 20], 30) == 2
assert circuit.encrypt_run_decrypt([0, 0, 0, 0], 0) == 0
print("make_array_index_of tests passed!")
compile_array_index_of()¶
Returns a compiled first-index-of search circuit.
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_array_index_of
circuit = compile_array_index_of(size=4, min_value=0, max_value=40)
assert circuit.encrypt_run_decrypt([10, 20, 30, 20], 20) == 1
assert circuit.encrypt_run_decrypt([10, 20, 30, 20], 30) == 2
print("compile_array_index_of tests passed!")
array_cumsum()¶
Prefix sums of array. Tests positive arrays, zero arrays, negative arrays, and mixed arrays.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_cumsum
def test_array_cumsum(arr):
return array_cumsum(arr)
compiler = fhe.Compiler(test_array_cumsum, {"arr": "encrypted"})
inputset = [([1, 2, 3],), ([0, 0, 0],), ([-1, 1, -1],), ([5, -2, -3],), ([-2, -3, -4],)]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([1, 2, 3]), [1, 3, 6])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0, 0]), [0, 0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-1, 1, -1]), [-1, 0, -1])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, -2, -3]), [5, 3, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-2, -3, -4]), [-2, -5, -9])
print("array_cumsum tests passed!")
array_reverse()¶
Reverses element order. Tests even length, odd length (implicitly by padding in FHE, but FHE arrays are fixed shape, so we test multiple static shapes).
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_reverse
def test_array_reverse(arr):
return array_reverse(arr)
compiler = fhe.Compiler(test_array_reverse, {"arr": "encrypted"})
inputset = [([1, 2, 3, 4],), ([0, 0, 0, 0],), ([5, -2, 3, 1],)]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([1, 2, 3, 4]), [4, 3, 2, 1])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0, 0, 0]), [0, 0, 0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([5, -2, 3, 1]), [1, 3, -2, 5])
# Test odd length
def test_array_reverse_odd(arr):
return array_reverse(arr)
compiler_odd = fhe.Compiler(test_array_reverse_odd, {"arr": "encrypted"})
circuit_odd = compiler_odd.compile([([1, 2, 3],), ([-1, -2, -3],)])
np.testing.assert_array_equal(circuit_odd.encrypt_run_decrypt([1, 2, 3]), [3, 2, 1])
print("array_reverse tests passed!")
array_concat()¶
Concatenates arrays. Tests normal concatenation, zeroes, negatives.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import array_concat
def test_array_concat(a1, a2):
return array_concat(a1, a2)
compiler = fhe.Compiler(test_array_concat, {"a1": "encrypted", "a2": "encrypted"})
inputset = [([1, 2], [3, 4]), ([0, 0], [0, 0]), ([-1, 1], [2, -2])]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([1, 2], [3, 4]), [1, 2, 3, 4])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0], [0, 0]), [0, 0, 0, 0])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-1, 1], [2, -2]), [-1, 1, 2, -2])
print("array_concat tests passed!")
make_top_k()¶
Creates a top_k reduction. Tests sorted, unsorted, zeroes, negatives, and duplicates.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import make_top_k
top_k_fn = make_top_k(size=4, k=2, min_value=-15, max_value=15)
def test_top_k(x):
return top_k_fn(x)
compiler = fhe.Compiler(test_top_k, {"x": "encrypted"})
inputset = [([4, 1, 3, 2],), ([10, 10, 0, -10],), ([1, 2, 3, 4],), ([-1, -2, -3, -4],), ([0, 0, 0, 0],)]
circuit = compiler.compile(inputset)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([4, 1, 3, 2]), [4, 3])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([10, 10, 0, -10]), [10, 10])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([1, 2, 3, 4]), [4, 3])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([-1, -2, -3, -4]), [-1, -2])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([0, 0, 0, 0]), [0, 0])
print("make_top_k tests passed!")
compile_top_k()¶
Returns a compiled top-k circuit.
import numpy as np
from concrete import fhe
from concrete_fhe_toolkit.arrays import compile_top_k
circuit = compile_top_k(size=4, k=2, min_value=-15, max_value=15)
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([4, 1, 3, 2]), [4, 3])
np.testing.assert_array_equal(circuit.encrypt_run_decrypt([10, 10, 0, -10]), [10, 10])
print("compile_top_k tests passed!")