mirror of
https://github.com/zama-ai/concrete.git
synced 2026-04-17 03:00:54 -04:00
docs: re-write documentation
This commit is contained in:
192
docs/basics/compatibility.md
Normal file
192
docs/basics/compatibility.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# Compatibility
|
||||
|
||||
## Supported operations
|
||||
|
||||
Here are the operations you can use inside the function you are compiling.
|
||||
|
||||
{% hint style="info" %}
|
||||
Some of these operations are not supported between two encrypted values. A detailed error will be raised if you try to do something that is not supported.
|
||||
{% endhint %}
|
||||
|
||||
### Supported Python operators
|
||||
|
||||
* [\_\_abs\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_abs\_\_)
|
||||
* [\_\_add\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_add\_\_)
|
||||
* [\_\_and\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_and\_\_)
|
||||
* [\_\_eq\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_eq\_\_)
|
||||
* [\_\_floordiv\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_floordiv\_\_)
|
||||
* [\_\_ge\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_ge\_\_)
|
||||
* [\_\_getitem\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_getitem\_\_)
|
||||
* [\_\_gt\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_gt\_\_)
|
||||
* [\_\_invert\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_invert\_\_)
|
||||
* [\_\_le\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_le\_\_)
|
||||
* [\_\_lshift\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_lshift\_\_)
|
||||
* [\_\_lt\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_lt\_\_)
|
||||
* [\_\_matmul\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_matmul\_\_)
|
||||
* [\_\_mod\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_mod\_\_)
|
||||
* [\_\_mul\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_mul\_\_)
|
||||
* [\_\_ne\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_ne\_\_)
|
||||
* [\_\_neg\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_neg\_\_)
|
||||
* [\_\_or\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_or\_\_)
|
||||
* [\_\_pos\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_pos\_\_)
|
||||
* [\_\_pow\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_pow\_\_)
|
||||
* [\_\_radd\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_radd\_\_)
|
||||
* [\_\_rand\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rand\_\_)
|
||||
* [\_\_rfloordiv\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rfloordiv\_\_)
|
||||
* [\_\_rlshift\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rlshift\_\_)
|
||||
* [\_\_rmatmul\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rmatmul\_\_)
|
||||
* [\_\_rmod\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rmod\_\_)
|
||||
* [\_\_rmul\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rmul\_\_)
|
||||
* [\_\_ror\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_ror\_\_)
|
||||
* [\_\_round\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_round\_\_)
|
||||
* [\_\_rpow\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rpow\_\_)
|
||||
* [\_\_rrshift\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rrshift\_\_)
|
||||
* [\_\_rshift\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rshift\_\_)
|
||||
* [\_\_rsub\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rsub\_\_)
|
||||
* [\_\_rtruediv\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rtruediv\_\_)
|
||||
* [\_\_rxor\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_rxor\_\_)
|
||||
* [\_\_sub\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_sub\_\_)
|
||||
* [\_\_truediv\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_truediv\_\_)
|
||||
* [\_\_xor\_\_](https://docs.python.org/3/reference/datamodel.html#object.\_\_xor\_\_)
|
||||
|
||||
### Supported NumPy functions
|
||||
|
||||
<!--- gen_supported_ufuncs.py: inject supported operations [BEGIN] -->
|
||||
<!--- do not edit, auto generated part by `python3 gen_supported_ufuncs.py` in docker -->
|
||||
* [np.absolute](https://numpy.org/doc/stable/reference/generated/numpy.absolute.html)
|
||||
* [np.add](https://numpy.org/doc/stable/reference/generated/numpy.add.html)
|
||||
* [np.arccos](https://numpy.org/doc/stable/reference/generated/numpy.arccos.html)
|
||||
* [np.arccosh](https://numpy.org/doc/stable/reference/generated/numpy.arccosh.html)
|
||||
* [np.arcsin](https://numpy.org/doc/stable/reference/generated/numpy.arcsin.html)
|
||||
* [np.arcsinh](https://numpy.org/doc/stable/reference/generated/numpy.arcsinh.html)
|
||||
* [np.arctan](https://numpy.org/doc/stable/reference/generated/numpy.arctan.html)
|
||||
* [np.arctan2](https://numpy.org/doc/stable/reference/generated/numpy.arctan2.html)
|
||||
* [np.arctanh](https://numpy.org/doc/stable/reference/generated/numpy.arctanh.html)
|
||||
* [np.around](https://numpy.org/doc/stable/reference/generated/numpy.around.html)
|
||||
* [np.bitwise\_and](https://numpy.org/doc/stable/reference/generated/numpy.bitwise\_and.html)
|
||||
* [np.bitwise\_or](https://numpy.org/doc/stable/reference/generated/numpy.bitwise\_or.html)
|
||||
* [np.bitwise\_xor](https://numpy.org/doc/stable/reference/generated/numpy.bitwise\_xor.html)
|
||||
* [np.cbrt](https://numpy.org/doc/stable/reference/generated/numpy.cbrt.html)
|
||||
* [np.ceil](https://numpy.org/doc/stable/reference/generated/numpy.ceil.html)
|
||||
* [np.clip](https://numpy.org/doc/stable/reference/generated/numpy.clip.html)
|
||||
* [np.concatenate](https://numpy.org/doc/stable/reference/generated/numpy.concatenate.html)
|
||||
* [np.copysign](https://numpy.org/doc/stable/reference/generated/numpy.copysign.html)
|
||||
* [np.cos](https://numpy.org/doc/stable/reference/generated/numpy.cos.html)
|
||||
* [np.cosh](https://numpy.org/doc/stable/reference/generated/numpy.cosh.html)
|
||||
* [np.deg2rad](https://numpy.org/doc/stable/reference/generated/numpy.deg2rad.html)
|
||||
* [np.degrees](https://numpy.org/doc/stable/reference/generated/numpy.degrees.html)
|
||||
* [np.dot](https://numpy.org/doc/stable/reference/generated/numpy.dot.html)
|
||||
* [np.equal](https://numpy.org/doc/stable/reference/generated/numpy.equal.html)
|
||||
* [np.exp](https://numpy.org/doc/stable/reference/generated/numpy.exp.html)
|
||||
* [np.exp2](https://numpy.org/doc/stable/reference/generated/numpy.exp2.html)
|
||||
* [np.expm1](https://numpy.org/doc/stable/reference/generated/numpy.expm1.html)
|
||||
* [np.fabs](https://numpy.org/doc/stable/reference/generated/numpy.fabs.html)
|
||||
* [np.float\_power](https://numpy.org/doc/stable/reference/generated/numpy.float\_power.html)
|
||||
* [np.floor](https://numpy.org/doc/stable/reference/generated/numpy.floor.html)
|
||||
* [np.floor\_divide](https://numpy.org/doc/stable/reference/generated/numpy.floor\_divide.html)
|
||||
* [np.fmax](https://numpy.org/doc/stable/reference/generated/numpy.fmax.html)
|
||||
* [np.fmin](https://numpy.org/doc/stable/reference/generated/numpy.fmin.html)
|
||||
* [np.fmod](https://numpy.org/doc/stable/reference/generated/numpy.fmod.html)
|
||||
* [np.gcd](https://numpy.org/doc/stable/reference/generated/numpy.gcd.html)
|
||||
* [np.greater](https://numpy.org/doc/stable/reference/generated/numpy.greater.html)
|
||||
* [np.greater\_equal](https://numpy.org/doc/stable/reference/generated/numpy.greater\_equal.html)
|
||||
* [np.heaviside](https://numpy.org/doc/stable/reference/generated/numpy.heaviside.html)
|
||||
* [np.hypot](https://numpy.org/doc/stable/reference/generated/numpy.hypot.html)
|
||||
* [np.invert](https://numpy.org/doc/stable/reference/generated/numpy.invert.html)
|
||||
* [np.isfinite](https://numpy.org/doc/stable/reference/generated/numpy.isfinite.html)
|
||||
* [np.isinf](https://numpy.org/doc/stable/reference/generated/numpy.isinf.html)
|
||||
* [np.isnan](https://numpy.org/doc/stable/reference/generated/numpy.isnan.html)
|
||||
* [np.lcm](https://numpy.org/doc/stable/reference/generated/numpy.lcm.html)
|
||||
* [np.ldexp](https://numpy.org/doc/stable/reference/generated/numpy.ldexp.html)
|
||||
* [np.left\_shift](https://numpy.org/doc/stable/reference/generated/numpy.left\_shift.html)
|
||||
* [np.less](https://numpy.org/doc/stable/reference/generated/numpy.less.html)
|
||||
* [np.less\_equal](https://numpy.org/doc/stable/reference/generated/numpy.less\_equal.html)
|
||||
* [np.log](https://numpy.org/doc/stable/reference/generated/numpy.log.html)
|
||||
* [np.log10](https://numpy.org/doc/stable/reference/generated/numpy.log10.html)
|
||||
* [np.log1p](https://numpy.org/doc/stable/reference/generated/numpy.log1p.html)
|
||||
* [np.log2](https://numpy.org/doc/stable/reference/generated/numpy.log2.html)
|
||||
* [np.logaddexp](https://numpy.org/doc/stable/reference/generated/numpy.logaddexp.html)
|
||||
* [np.logaddexp2](https://numpy.org/doc/stable/reference/generated/numpy.logaddexp2.html)
|
||||
* [np.logical\_and](https://numpy.org/doc/stable/reference/generated/numpy.logical\_and.html)
|
||||
* [np.logical\_not](https://numpy.org/doc/stable/reference/generated/numpy.logical\_not.html)
|
||||
* [np.logical\_or](https://numpy.org/doc/stable/reference/generated/numpy.logical\_or.html)
|
||||
* [np.logical\_xor](https://numpy.org/doc/stable/reference/generated/numpy.logical\_xor.html)
|
||||
* [np.matmul](https://numpy.org/doc/stable/reference/generated/numpy.matmul.html)
|
||||
* [np.maximum](https://numpy.org/doc/stable/reference/generated/numpy.maximum.html)
|
||||
* [np.minimum](https://numpy.org/doc/stable/reference/generated/numpy.minimum.html)
|
||||
* [np.multiply](https://numpy.org/doc/stable/reference/generated/numpy.multiply.html)
|
||||
* [np.negative](https://numpy.org/doc/stable/reference/generated/numpy.negative.html)
|
||||
* [np.nextafter](https://numpy.org/doc/stable/reference/generated/numpy.nextafter.html)
|
||||
* [np.not\_equal](https://numpy.org/doc/stable/reference/generated/numpy.not\_equal.html)
|
||||
* [np.ones\_like](https://numpy.org/doc/stable/reference/generated/numpy.ones\_like.html)
|
||||
* [np.positive](https://numpy.org/doc/stable/reference/generated/numpy.positive.html)
|
||||
* [np.power](https://numpy.org/doc/stable/reference/generated/numpy.power.html)
|
||||
* [np.rad2deg](https://numpy.org/doc/stable/reference/generated/numpy.rad2deg.html)
|
||||
* [np.radians](https://numpy.org/doc/stable/reference/generated/numpy.radians.html)
|
||||
* [np.reciprocal](https://numpy.org/doc/stable/reference/generated/numpy.reciprocal.html)
|
||||
* [np.remainder](https://numpy.org/doc/stable/reference/generated/numpy.remainder.html)
|
||||
* [np.reshape](https://numpy.org/doc/stable/reference/generated/numpy.reshape.html)
|
||||
* [np.right\_shift](https://numpy.org/doc/stable/reference/generated/numpy.right\_shift.html)
|
||||
* [np.rint](https://numpy.org/doc/stable/reference/generated/numpy.rint.html)
|
||||
* [np.round\_](https://numpy.org/doc/stable/reference/generated/numpy.round\_.html)
|
||||
* [np.sign](https://numpy.org/doc/stable/reference/generated/numpy.sign.html)
|
||||
* [np.signbit](https://numpy.org/doc/stable/reference/generated/numpy.signbit.html)
|
||||
* [np.sin](https://numpy.org/doc/stable/reference/generated/numpy.sin.html)
|
||||
* [np.sinh](https://numpy.org/doc/stable/reference/generated/numpy.sinh.html)
|
||||
* [np.spacing](https://numpy.org/doc/stable/reference/generated/numpy.spacing.html)
|
||||
* [np.sqrt](https://numpy.org/doc/stable/reference/generated/numpy.sqrt.html)
|
||||
* [np.square](https://numpy.org/doc/stable/reference/generated/numpy.square.html)
|
||||
* [np.subtract](https://numpy.org/doc/stable/reference/generated/numpy.subtract.html)
|
||||
* [np.sum](https://numpy.org/doc/stable/reference/generated/numpy.sum.html)
|
||||
* [np.tan](https://numpy.org/doc/stable/reference/generated/numpy.tan.html)
|
||||
* [np.tanh](https://numpy.org/doc/stable/reference/generated/numpy.tanh.html)
|
||||
* [np.transpose](https://numpy.org/doc/stable/reference/generated/numpy.transpose.html)
|
||||
* [np.true\_divide](https://numpy.org/doc/stable/reference/generated/numpy.true\_divide.html)
|
||||
* [np.trunc](https://numpy.org/doc/stable/reference/generated/numpy.trunc.html)
|
||||
* [np.where](https://numpy.org/doc/stable/reference/generated/numpy.where.html)
|
||||
* [np.zeros\_like](https://numpy.org/doc/stable/reference/generated/numpy.zeros\_like.html)
|
||||
<!--- gen_supported_ufuncs.py: inject supported operations [END] -->
|
||||
|
||||
### Supported `ndarray` methods
|
||||
|
||||
* [np.ndarray.astype](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.astype.html)
|
||||
* [np.ndarray.clip](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.clip.html)
|
||||
* [np.ndarray.dot](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.dot.html)
|
||||
* [np.ndarray.flatten](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.flatten.html)
|
||||
* [np.ndarray.reshape](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.reshape.html)
|
||||
* [np.ndarray.transpose](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.transpose.html)
|
||||
|
||||
### Supported `ndarray` properties
|
||||
|
||||
* [np.ndarray.shape](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html)
|
||||
* [np.ndarray.ndim](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.ndim.html)
|
||||
* [np.ndarray.size](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.size.html)
|
||||
* [np.ndarray.T](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.T.html)
|
||||
|
||||
## Limitations
|
||||
|
||||
### Operational constraints
|
||||
|
||||
Some Python control flow statements are not supported. For example, you cannot have an `if` statement or a `while` statement for which the condition depends on an encrypted value. However, such statements are supported with constant values (e.g., `for i in range(SOME_CONSTANT)`, `if os.environ.get("SOME_FEATURE") == "ON":`).
|
||||
|
||||
Another constraint is that you cannot have floating-point inputs or floating-point outputs. You can have floating-point intermediate values as long as they can be converted to an integer Table Lookup (e.g., `(60 * np.sin(x)).astype(np.int64)`).
|
||||
|
||||
### Bit width constraints
|
||||
|
||||
There is a limit on the bit width of encrypted values. We are constantly working on increasing this bit width. If you go above this limit, you will get an error.
|
||||
|
||||
### Computation constraints
|
||||
|
||||
One of the most common operations in **Concrete Numpy** is `Table Lookups` (TLUs). TLUs are performed with an FHE operation called `Programmable Bootstrapping` (PBS). PBSes have a certain probability of error, which, when triggered, result in inaccurate results.
|
||||
|
||||
Let's say you have the table:
|
||||
|
||||
```python
|
||||
[1, 4, 9, 16, 25, 36, 49, 64]
|
||||
```
|
||||
|
||||
And you performed a table lookup using `4`, The result you should get is `16`, but because of the possibility of error, you can sometimes get `9` or `25`.
|
||||
|
||||
{% hint style="info" %}
|
||||
The probability of this error can be configured through the `p_error` configuration option, which has the default value of `0.000063342483999973` (i.e., probability of success is `99.993`%). Keep in mind that changing it could affect compilation and key generation times.
|
||||
{% endhint %}
|
||||
@@ -1,103 +0,0 @@
|
||||
# Compiling and Executing your first function
|
||||
|
||||
## Importing necessary components
|
||||
|
||||
Everything you need to compile and execute homomorphic functions is included in a single module. You can import it like so:
|
||||
|
||||
```python
|
||||
import concrete.numpy as cnp
|
||||
```
|
||||
|
||||
## Defining a function to compile
|
||||
|
||||
You need to have a python function that follows the [limits](../explanation/fhe\_and\_framework_limits.md) of **Concrete Numpy**. Here is a simple example:
|
||||
|
||||
<!--pytest-codeblocks:cont-->
|
||||
```python
|
||||
def f(x, y):
|
||||
return x + y
|
||||
```
|
||||
|
||||
## Compiling the function
|
||||
|
||||
To compile the function, you need to identify the inputs that it is expecting. In the example function above, `x` and `y` could be scalars or tensors (though, for now, only dot between tensors are supported), they can be encrypted or clear, they can be signed or unsigned, they can have different bit-widths. So, we need to know what they are beforehand. We can do that like so:
|
||||
|
||||
<!--pytest-codeblocks:cont-->
|
||||
```python
|
||||
x = "encrypted"
|
||||
y = "encrypted"
|
||||
```
|
||||
|
||||
In this configuration, both `x` and `y` will be encrypted values.
|
||||
|
||||
We also need an inputset. It is to determine the bit-widths of the intermediate results. It should be an iterable yielding tuples in the same order as the inputs of the function to compile. There should be at least 10 inputs in the input set to avoid warnings (except for functions with less than 10 possible inputs). The warning is there because the bigger the input set, the better the bounds will be.
|
||||
|
||||
<!--pytest-codeblocks:cont-->
|
||||
```python
|
||||
inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, 5), (5, 4)]
|
||||
```
|
||||
|
||||
Finally, we can compile our function to its homomorphic equivalent.
|
||||
|
||||
<!--pytest-codeblocks:cont-->
|
||||
```python
|
||||
compiler = cnp.Compiler(f, {"x": x, "y": y})
|
||||
circuit = compiler.compile(inputset)
|
||||
|
||||
# You can print the compiled circuit:
|
||||
print(circuit)
|
||||
|
||||
# Outputs
|
||||
|
||||
# %0 = x # EncryptedScalar<uint3>
|
||||
# %1 = y # EncryptedScalar<uint3>
|
||||
# %2 = add(%0, %1) # EncryptedScalar<uint4>
|
||||
# return %2
|
||||
|
||||
# Or draw it
|
||||
circuit.draw(show=True)
|
||||
```
|
||||
|
||||
Here is the graph from the previous code block drawn with `draw`:
|
||||
|
||||

|
||||
|
||||
## Performing homomorphic evaluation
|
||||
|
||||
You can use `.encrypt_run_decrypt(...)` method of `Circuit` to perform fully homomorphic evaluation. Here are some examples:
|
||||
|
||||
<!--pytest-codeblocks:cont-->
|
||||
```python
|
||||
circuit.encrypt_run_decrypt(3, 4)
|
||||
# 7
|
||||
circuit.encrypt_run_decrypt(1, 2)
|
||||
# 3
|
||||
circuit.encrypt_run_decrypt(7, 7)
|
||||
# 14
|
||||
circuit.encrypt_run_decrypt(0, 0)
|
||||
# 0
|
||||
```
|
||||
|
||||
{% hint style="warning" %}
|
||||
Be careful about the inputs, though. If you were to run with values outside the range of the inputset, the result might not be correct.
|
||||
{% endhint %}
|
||||
|
||||
While `.encrypt_run_decrypt(...)` is a good start for prototyping examples, more advanced usages require control over the different steps that are happening behind the scene, mainly key generation, encryption, execution, and decryption. The different steps can of course be called separately as in the example below:
|
||||
|
||||
<!--pytest-codeblocks:cont-->
|
||||
```python
|
||||
# generate keys required for encrypted computation
|
||||
circuit.keygen()
|
||||
# this will encrypt arguments that require encryption and pack all arguments
|
||||
# as well as public materials (public keys)
|
||||
public_args = circuit.encrypt(3, 4)
|
||||
# this will run the encrypted computation using public materials and inputs provided
|
||||
encrypted_result = circuit.run(public_args)
|
||||
# the execution returns the encrypted result which can later be decrypted
|
||||
decrypted_result = circuit.decrypt(encrypted_result)
|
||||
```
|
||||
|
||||
## Further reading
|
||||
|
||||
* [Working With Floating Points Tutorial](../tutorial/working\_with\_floating\_points.md)
|
||||
* [Table Lookup Tutorial](../tutorial/table\_lookup.md)
|
||||
@@ -1,62 +1,55 @@
|
||||
# Installing
|
||||
# Installation
|
||||
|
||||
## Python package
|
||||
**Concrete Numpy** is natively supported on Linux and macOS for Python 3.8 and 3.9, but if you have Docker support in your platform, you can use the docker image to use **Concrete Numpy**.
|
||||
|
||||
To install **Concrete Numpy** from PyPi, run the following:
|
||||
## Using PyPI
|
||||
|
||||
You can install **Concrete Numpy** from PyPI:
|
||||
|
||||
```shell
|
||||
pip install concrete-numpy
|
||||
```
|
||||
|
||||
{% hint style='info' %}
|
||||
Note that **concrete-numpy** has `pygraphviz` as an optional dependency to draw graphs.
|
||||
{% hint style="warning" %}
|
||||
Apple silicon users must use docker installation (explained below) as there is no ARM version of some of our dependencies for the time being.
|
||||
{% endhint %}
|
||||
|
||||
{% hint style='info' %}
|
||||
`pygraphviz` requires `graphviz` packages being installed on your OS, see <a href="https://pygraphviz.github.io/documentation/stable/install.html">https://pygraphviz.github.io/documentation/stable/install.html</a>
|
||||
{% endhint %}
|
||||
|
||||
{% hint style='tip' %}
|
||||
`graphviz` packages are binary packages that won't automatically be installed by pip.
|
||||
Do check <a href="https://pygraphviz.github.io/documentation/stable/install.html">https://pygraphviz.github.io/documentation/stable/install.html</a> for instructions on how to install `graphviz` for `pygraphviz`.
|
||||
{% endhint %}
|
||||
|
||||
You can install the extra python dependencies for drawing with:
|
||||
You can install the extra python dependencies for drawing circuits:
|
||||
|
||||
```shell
|
||||
pip install concrete-numpy[full]
|
||||
# you may need to force reinstallation
|
||||
pip install --force-reinstall concrete-numpy[full]
|
||||
```
|
||||
|
||||
## Docker image
|
||||
{% hint style="info" %}
|
||||
**Concrete Numpy** depends on `pygraphviz` for drawing, which requires `graphviz` packages to be installed on your system (see [pygraphviz installation documentation](https://pygraphviz.github.io/documentation/stable/install.html)).
|
||||
{% endhint %}
|
||||
|
||||
You can also get the **concrete-numpy** docker image by either pulling the latest docker image or a specific version:
|
||||
## Using Docker
|
||||
|
||||
You can also get the **Concrete Numpy** docker image:
|
||||
|
||||
```shell
|
||||
docker pull zamafhe/concrete-numpy:latest
|
||||
# or
|
||||
docker pull zamafhe/concrete-numpy:v0.2.0
|
||||
docker pull zamafhe/concrete-numpy:v0.6.0
|
||||
```
|
||||
|
||||
The image can be used with docker volumes, [see the docker documentation here](https://docs.docker.com/storage/volumes/).
|
||||
### Starting Jupyter server
|
||||
|
||||
You can then use this image with the following command:
|
||||
By default, the entry point of the **Concrete Numpy** docker image is a jupyter server that you can access from your browser:
|
||||
|
||||
```shell
|
||||
docker run --rm -it -p 8888:8888 zamafhe/concrete-numpy:v0.2.0
|
||||
docker run --rm -it -p 8888:8888 zamafhe/concrete-numpy:latest
|
||||
```
|
||||
|
||||
or with local volume to save notebooks on host:
|
||||
|
||||
```
|
||||
docker run --rm -it -p 8888:8888 -v /host/path:/data zamafhe/concrete-numpy:v0.2.0
|
||||
```
|
||||
|
||||
This will launch a **Concrete Numpy** enabled jupyter server in the docker, that you can access from your browser.
|
||||
|
||||
Alternatively, you can just open a shell in the docker with or without volumes:
|
||||
To save notebooks on host, you can use a local volume:
|
||||
|
||||
```shell
|
||||
docker run --rm -it zamafhe/concrete-numpy:v0.2.0 /bin/bash
|
||||
docker run --rm -it -p 8888:8888 -v /path/to/notebooks:/data zamafhe/concrete-numpy:latest
|
||||
```
|
||||
|
||||
### Starting Bash session
|
||||
|
||||
Alternatively, you can launch a Bash session:
|
||||
|
||||
```shell
|
||||
docker run --rm -it zamafhe/concrete-numpy:latest /bin/bash
|
||||
```
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
# Numpy Support
|
||||
|
||||
In this section, we list the operations which are supported currently in **Concrete Numpy**. Please have a look to numpy [documentation](https://numpy.org/doc/stable/user/index.html) to know what these operations are about.
|
||||
|
||||
<!--- gen_supported_ufuncs.py: inject supported operations [BEGIN] -->
|
||||
<!--- do not edit, auto generated part by `python3 gen_supported_ufuncs.py` in docker -->
|
||||
List of supported functions:
|
||||
- absolute
|
||||
- add
|
||||
- arccos
|
||||
- arccosh
|
||||
- arcsin
|
||||
- arcsinh
|
||||
- arctan
|
||||
- arctan2
|
||||
- arctanh
|
||||
- around
|
||||
- bitwise_and
|
||||
- bitwise_or
|
||||
- bitwise_xor
|
||||
- cbrt
|
||||
- ceil
|
||||
- clip
|
||||
- concatenate
|
||||
- copysign
|
||||
- cos
|
||||
- cosh
|
||||
- deg2rad
|
||||
- degrees
|
||||
- dot
|
||||
- equal
|
||||
- exp
|
||||
- exp2
|
||||
- expm1
|
||||
- fabs
|
||||
- float_power
|
||||
- floor
|
||||
- floor_divide
|
||||
- fmax
|
||||
- fmin
|
||||
- fmod
|
||||
- gcd
|
||||
- greater
|
||||
- greater_equal
|
||||
- heaviside
|
||||
- hypot
|
||||
- invert
|
||||
- isfinite
|
||||
- isinf
|
||||
- isnan
|
||||
- lcm
|
||||
- ldexp
|
||||
- left_shift
|
||||
- less
|
||||
- less_equal
|
||||
- log
|
||||
- log10
|
||||
- log1p
|
||||
- log2
|
||||
- logaddexp
|
||||
- logaddexp2
|
||||
- logical_and
|
||||
- logical_not
|
||||
- logical_or
|
||||
- logical_xor
|
||||
- matmul
|
||||
- maximum
|
||||
- minimum
|
||||
- multiply
|
||||
- negative
|
||||
- nextafter
|
||||
- not_equal
|
||||
- ones_like
|
||||
- positive
|
||||
- power
|
||||
- rad2deg
|
||||
- radians
|
||||
- reciprocal
|
||||
- remainder
|
||||
- reshape
|
||||
- right_shift
|
||||
- rint
|
||||
- round_
|
||||
- sign
|
||||
- signbit
|
||||
- sin
|
||||
- sinh
|
||||
- spacing
|
||||
- sqrt
|
||||
- square
|
||||
- subtract
|
||||
- sum
|
||||
- tan
|
||||
- tanh
|
||||
- transpose
|
||||
- true_divide
|
||||
- trunc
|
||||
- where
|
||||
- zeros_like
|
||||
<!--- gen_supported_ufuncs.py: inject supported operations [END] -->
|
||||
|
||||
# Shapes
|
||||
|
||||
Our encrypted tensors have shapes just like numpy arrays.
|
||||
We determine the shapes of the inputs from the inputset, and we infer the shapes of the intermediate values from the function that is being compiled.
|
||||
|
||||
You can access the shape of a tensor by accessing the `shape` property, just like in numpy.
|
||||
Here is an example:
|
||||
|
||||
```python
|
||||
def function_to_compile(x):
|
||||
return x.reshape((x.shape[0], -1))
|
||||
```
|
||||
|
||||
One important aspect of our library is that, scalars are tensors of shape `()`.
|
||||
This is transparent to you, as a user, but it's something to keep in mind, especialy if you are accessing the `shape` property in the functions that you are compiling.
|
||||
This schema is used by numpy and pytorch as well.
|
||||
|
||||
## Indexing
|
||||
|
||||
Indexing is described in [this section](../tutorial/indexing.md).
|
||||
|
||||
## Other machine-learning-related operators
|
||||
|
||||
We support (sometimes, with limits) some other operators:
|
||||
|
||||
- dot: one of the operators must be non-encrypted
|
||||
- clip: the minimum and maximum values must be constant
|
||||
- transpose
|
||||
- ravel
|
||||
- reshape: the shapes must be constant
|
||||
- flatten
|
||||
- matmul: one of the two matrices must be non-encrypted. Only 2D matrix multiplication is supported for now
|
||||
|
||||
## Operators which are not numpy-restricted
|
||||
|
||||
The framework also gives support for:
|
||||
|
||||
- shifts, i.e., `x op y` for `op` in `[<<, >>, ]`: if one of `x` or `y` is a constant
|
||||
- boolean test operations, i.e., `x op y` for `op` in `[<, <=, ==, !=, >, >=]`: if one of `x` or `y` is a constant
|
||||
- boolean operators, i.e., `x op y` for `op` in `[&, ^, |]`: if one of `x` or `y` is a constant
|
||||
- powers, i.e., `x ** y`: if one of `x` or `y` is a constant
|
||||
- modulo, i.e., `x % y`: if one of `x` or `y` is a constant
|
||||
- invert, i.e., `~x`
|
||||
- true div, i.e., `x / y`: if one of `x` or `y` is a constant
|
||||
- floor div, i.e., `x // y`: if one of `x` or `y` is a constant
|
||||
|
||||
There is support for astype as well, e.g. `x.astype(numpy.int64)`. This allows to control which data type to use for computations. In the context of FHE going back to integers may allow to fuse floating point operations together, see [this tutorial](../tutorial/working_with_floating_points.md) to see how to work with floating point values.
|
||||
86
docs/basics/quick_start.md
Normal file
86
docs/basics/quick_start.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Quick Start
|
||||
|
||||
To compute on encrypted data, you first need to define the function that you want to compute, then compile it into a Concrete Numpy `Circuit`, which you can use to perform homomorphic evaluation.
|
||||
|
||||
Here is the full example that we will walk through:
|
||||
|
||||
```python
|
||||
import concrete.numpy as cnp
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
compiler = cnp.Compiler(add, {"x": "encrypted", "y": "clear"})
|
||||
|
||||
inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1)]
|
||||
circuit = compiler.compile(inputset)
|
||||
|
||||
x = 4
|
||||
y = 4
|
||||
|
||||
clear_evaluation = add(x, y)
|
||||
homomorphic_evaluation = circuit.encrypt_run_decrypt(x, y)
|
||||
|
||||
print(x, "+", y, "=", clear_evaluation, "=", homomorphic_evaluation)
|
||||
```
|
||||
|
||||
## Importing the library
|
||||
|
||||
Everything you need to perform homomorphic evaluation is included in a single module:
|
||||
|
||||
<!--pytest-codeblocks:skip-->
|
||||
```python
|
||||
import concrete.numpy as cnp
|
||||
```
|
||||
|
||||
## Defining the function to compile
|
||||
|
||||
In this example, we will compile a simple addition function:
|
||||
|
||||
<!--pytest-codeblocks:skip-->
|
||||
```python
|
||||
def add(x, y):
|
||||
return x + y
|
||||
```
|
||||
|
||||
## Creating a compiler
|
||||
|
||||
To compile the function, you need to create a `Compiler` by specifying the function to compile and encryption status of its inputs:
|
||||
|
||||
<!--pytest-codeblocks:skip-->
|
||||
```python
|
||||
compiler = cnp.Compiler(add, {"x": "encrypted", "y": "clear"})
|
||||
```
|
||||
|
||||
## Defining an inputset
|
||||
|
||||
An inputset is a collection representing the typical inputs to the function. It is used to determine the bit widths and shapes of the variables within the function.
|
||||
|
||||
It should be an iterable, yielding tuples of the same length as the number of arguments of the function being compiled:
|
||||
|
||||
<!--pytest-codeblocks:skip-->
|
||||
```python
|
||||
inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1)]
|
||||
```
|
||||
|
||||
## Compiling the function
|
||||
|
||||
You can use the `compile` method of a `Compiler` class with an inputset to perform the compilation and get the resulting circuit back:
|
||||
|
||||
<!--pytest-codeblocks:skip-->
|
||||
```python
|
||||
circuit = compiler.compile(inputset)
|
||||
```
|
||||
|
||||
## Performing homomorphic evaluation
|
||||
|
||||
You can use the `encrypt_run_decrypt` method of a `Circuit` class to perform homomorphic evaluation:
|
||||
|
||||
<!--pytest-codeblocks:skip-->
|
||||
```python
|
||||
homomorphic_evaluation = circuit.encrypt_run_decrypt(4, 4)
|
||||
```
|
||||
|
||||
{% hint style="info" %}
|
||||
`circuit.encrypt_run_decrypt(*args)` is just a convenient way to do everything at once. It is implemented as `circuit.decrypt(circuit.run(circuit.encrypt(*args)))`.
|
||||
{% endhint %}
|
||||
Reference in New Issue
Block a user