Extensions
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 np
from concrete import fhe
def complex_univariate_function(x):
def per_element(element):
result = 0
for i in range(element):
result += i
return result
return np.vectorize(per_element)(x)
@fhe.compiler({"x": "encrypted"})
def f(x):
return fhe.univariate(complex_univariate_function)(x)
inputset = [np.random.randint(0, 5, size=(3, 2)) for _ in range(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.shapeshould be the same withinput.shape)each output element should correspond to a single input element (e.g.,
output[0]should only depend oninput[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:
Only 2D convolutions without padding and with one group are currently supported.
fhe.maxpool(...)
Allows you to perform a maxpool operation, with the same semantic as onnx.MaxPool:
Only 2D maxpooling without padding and up to 15-bits is currently supported.
fhe.array(...)
Allows you to create encrypted arrays:
Currently, only scalars can be used to create arrays.
fhe.zero()
Allows you to create an encrypted scalar zero:
fhe.zeros(shape)
Allows you to create an encrypted tensor of zeros:
fhe.one()
Allows you to create an encrypted scalar one:
fhe.ones(shape)
Allows you to create an encrypted tensor of ones:
fhe.hint(value, **kwargs)
Allows you to hint properties of a value. Imagine you have this circuit:
You'd expect all of a, b, and c to be 8-bits, but because inputset is very small, this code could print:
The first solution in these cases should be to use a bigger inputset, but it can still be tricky to solve with the inputset. That's where hint extension comes into play. Hints are a way to provide extra information to compilation process:
Bit-width hints are for constraining the minimum number of bits in the encoded the value. If you hint a value to be 8-bits, it means it should be at least
uint8orint8.
To fix f using hints, you can do:
Hints are only applied to the value being hinted, and no other value. If you want the hint to be applied to multiple values, you need to hint all of them.
you'll always see:
regardless of the bounds.
Last updated
Was this helpful?