Concrete supports native Python and NumPy operations as much as possible, but not everything in Python or NumPy is available. Therefore, we provide some extensions ourselves to improve your experience.
fhe.univariate(function)
Allows you to wrap any univariate function into a single table lookup:
import numpy as npfrom concrete import fhedefcomplex_univariate_function(x):defper_element(element): result =0for i inrange(element): result += ireturn resultreturn np.vectorize(per_element)(x)@fhe.compiler({"x": "encrypted"})deff(x):return fhe.univariate(complex_univariate_function)(x)inputset = [np.random.randint(0, 5, size=(3, 2))for _ inrange(10)]circuit = f.compile(inputset)sample = np.array([ [0, 4], [2, 1], [3, 0],])assert np.array_equal(circuit.encrypt_run_decrypt(sample), complex_univariate_function(sample))
The wrapped function:
shouldn't have any side effects (e.g., no modification of global state)
should be deterministic (e.g., no random numbers)
should have the same output shape as its input (i.e., output.shape should be the same with input.shape)
each output element should correspond to a single input element (e.g., output[0] should only depend on input[0])
If any of these constraints are violated, the outcome is undefined.
fhe.conv(...)
Allows you to perform a convolution operation, with the same semantic as onnx.Conv:
Currently, only scalars can be used to create arrays.
fhe.zero()
Allows you to create an encrypted scalar zero:
from concrete import fheimport numpy as np@fhe.compiler({"x": "encrypted"})deff(x): z = fhe.zero()return x + zinputset =range(10)circuit = f.compile(inputset)for x inrange(10):assert circuit.encrypt_run_decrypt(x)== x
fhe.zeros(shape)
Allows you to create an encrypted tensor of zeros:
from concrete import fheimport numpy as np@fhe.compiler({"x": "encrypted"})deff(x): z = fhe.zeros((2, 3))return x + zinputset =range(10)circuit = f.compile(inputset)for x inrange(10):assert np.array_equal(circuit.encrypt_run_decrypt(x), np.array([[x, x, x], [x, x, x]]))
fhe.one()
Allows you to create an encrypted scalar one:
from concrete import fheimport numpy as np@fhe.compiler({"x": "encrypted"})deff(x): z = fhe.one()return x + zinputset =range(10)circuit = f.compile(inputset)for x inrange(10):assert circuit.encrypt_run_decrypt(x)== x +1
fhe.ones(shape)
Allows you to create an encrypted tensor of ones:
from concrete import fheimport numpy as np@fhe.compiler({"x": "encrypted"})deff(x): z = fhe.ones((2, 3))return x + zinputset =range(10)circuit = f.compile(inputset)for x inrange(10):assert np.array_equal(circuit.encrypt_run_decrypt(x), np.array([[x, x, x], [x, x, x]]) +1)