docs: re-write documentation

This commit is contained in:
aquint-zama
2022-06-01 15:41:37 +02:00
committed by Umut
parent 546ed48765
commit 35e46aca69
53 changed files with 1505 additions and 1673 deletions

View 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 %}

View File

@@ -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`:
![Drawn graph of previous code block](../\_static/basics/compiling\_and\_executing\_example\_graph.png)
## 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)

View File

@@ -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
```

View File

@@ -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.

View 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 %}