diff --git a/docs/dev/explanation/compilation.md b/docs/dev/explanation/compilation.md index 3d7edfe78..52efb745b 100644 --- a/docs/dev/explanation/compilation.md +++ b/docs/dev/explanation/compilation.md @@ -25,7 +25,7 @@ inputset = [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)] circuit = compiler.compile_on_inputset(inputset) # Make homomorphic inference -circuit.run(1, 0) +circuit.encrypt_run_decrypt(1, 0) ``` ## Overview of the numpy compilation process diff --git a/docs/user/basics/compiling_and_executing.md b/docs/user/basics/compiling_and_executing.md index 560acae7a..8b8e0d4b0 100644 --- a/docs/user/basics/compiling_and_executing.md +++ b/docs/user/basics/compiling_and_executing.md @@ -78,17 +78,17 @@ Here is the graph from the previous code block drawn with `draw_graph`: ## Performing homomorphic evaluation -You can use `.run(...)` method of `FHECircuit` returned by `hnp.compile_numpy_function(...)` to perform fully homomorphic evaluation. Here are some examples: +You can use `.encrypt_run_decrypt(...)` method of `FHECircuit` returned by `hnp.compile_numpy_function(...)` to perform fully homomorphic evaluation. Here are some examples: ```python -circuit.run(3, 4) +circuit.encrypt_run_decrypt(3, 4) # 7 -circuit.run(1, 2) +circuit.encrypt_run_decrypt(1, 2) # 3 -circuit.run(7, 7) +circuit.encrypt_run_decrypt(7, 7) # 14 -circuit.run(0, 0) +circuit.encrypt_run_decrypt(0, 0) # 0 ``` @@ -97,11 +97,20 @@ 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. ``` -Today, we cannot simulate a client / server API in python, but it is for very soon. Then, we will have: - - a `keygen` API, which is used to generate both public and private keys - - an `encrypt` API, which happens on the user's device, and is using private keys - - a `run_inference` API, which happens on the untrusted server and only uses public material - - a `encrypt` API, which happens on the user's device to get final clear result, and is using private keys +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: + + +```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 diff --git a/docs/user/tutorial/indexing.md b/docs/user/tutorial/indexing.md index 42c4e8bf2..f79b8595b 100644 --- a/docs/user/tutorial/indexing.md +++ b/docs/user/tutorial/indexing.md @@ -23,7 +23,7 @@ circuit = compiler.compile_on_inputset(inputset) test_input = np.array([4, 2, 6], dtype=np.uint8) expected_output = 2 -assert np.array_equal(circuit.run(test_input), expected_output) +assert np.array_equal(circuit.encrypt_run_decrypt(test_input), expected_output) ``` You can use negative indexing. @@ -43,7 +43,7 @@ circuit = compiler.compile_on_inputset(inputset) test_input = np.array([4, 2, 6], dtype=np.uint8) expected_output = 6 -assert np.array_equal(circuit.run(test_input), expected_output) +assert np.array_equal(circuit.encrypt_run_decrypt(test_input), expected_output) ``` You can use multidimensional indexing as well. @@ -63,7 +63,7 @@ circuit = compiler.compile_on_inputset(inputset) test_input = np.array([[4, 2], [1, 5], [7, 6]], dtype=np.uint8) expected_output = 6 -assert np.array_equal(circuit.run(test_input), expected_output) +assert np.array_equal(circuit.encrypt_run_decrypt(test_input), expected_output) ``` ### Extracting a slice @@ -83,7 +83,7 @@ circuit = compiler.compile_on_inputset(inputset) test_input = np.array([4, 2, 6, 1, 7], dtype=np.uint8) expected_output = np.array([2, 6, 1], dtype=np.uint8) -assert np.array_equal(circuit.run(test_input), expected_output) +assert np.array_equal(circuit.encrypt_run_decrypt(test_input), expected_output) ``` You can use multidimensional slicing as well. diff --git a/docs/user/tutorial/table_lookup.md b/docs/user/tutorial/table_lookup.md index fed967ca0..73b36874f 100644 --- a/docs/user/tutorial/table_lookup.md +++ b/docs/user/tutorial/table_lookup.md @@ -23,10 +23,10 @@ results in ```python -circuit.run(0) == 2 -circuit.run(1) == 1 -circuit.run(2) == 3 -circuit.run(3) == 0 +circuit.encrypt_run_decrypt(0) == 2 +circuit.encrypt_run_decrypt(1) == 1 +circuit.encrypt_run_decrypt(2) == 3 +circuit.encrypt_run_decrypt(3) == 0 ``` Moreover, direct lookup tables can be used with tensors where the same table lookup is applied to each value in the tensor, so @@ -38,7 +38,7 @@ results in ```python input = np.array([[0, 1, 3], [2, 3, 1]], dtype=np.uint8) -circuit.run(input) == [[2, 1, 0], [3, 0, 1]] +circuit.encrypt_run_decrypt(input) == [[2, 1, 0], [3, 0, 1]] ``` ## Direct Multi Table Lookup @@ -71,7 +71,7 @@ results in ```python input = np.array([[2, 3], [1, 2], [3, 0]], dtype=np.uint8) -circuit.run(input) == [[4, 27], [1, 8], [9, 0]] +circuit.encrypt_run_decrypt(input) == [[4, 27], [1, 8], [9, 0]] ``` Basically, we applied `squared` table to the first column and `cubed` to the second one. @@ -96,14 +96,14 @@ results in ```python -circuit.run(0) == 77 -circuit.run(1) == 35 -circuit.run(2) == 32 -circuit.run(3) == 70 -circuit.run(4) == 115 -circuit.run(5) == 125 -circuit.run(6) == 91 -circuit.run(7) == 45 +circuit.encrypt_run_decrypt(0) == 77 +circuit.encrypt_run_decrypt(1) == 35 +circuit.encrypt_run_decrypt(2) == 32 +circuit.encrypt_run_decrypt(3) == 70 +circuit.encrypt_run_decrypt(4) == 115 +circuit.encrypt_run_decrypt(5) == 125 +circuit.encrypt_run_decrypt(6) == 91 +circuit.encrypt_run_decrypt(7) == 45 ``` Initially, the function is converted to this operation graph diff --git a/docs/user/tutorial/tensor_operations.ipynb b/docs/user/tutorial/tensor_operations.ipynb index 76ca12e0b..f444a661f 100644 --- a/docs/user/tutorial/tensor_operations.ipynb +++ b/docs/user/tutorial/tensor_operations.ipynb @@ -540,7 +540,7 @@ " \n", " # We setup an example tensor that will be encrypted and passed on to the current operation\n", " sample = np.random.randint(3, 11, size=(3, 2), dtype=np.uint8)\n", - " result = circuit.run(sample)\n", + " result = circuit.encrypt_run_decrypt(sample)\n", " \n", " print(\"#######################################################################################\")\n", " print()\n", diff --git a/docs/user/tutorial/working_with_floating_points.md b/docs/user/tutorial/working_with_floating_points.md index 76241b613..18d885c2c 100644 --- a/docs/user/tutorial/working_with_floating_points.md +++ b/docs/user/tutorial/working_with_floating_points.md @@ -15,11 +15,11 @@ def f(x): compiler = hnp.NPFHECompiler(f, {"x": "encrypted"}) circuit = compiler.compile_on_inputset(range(64)) -print(circuit.run(3) == f(3)) -print(circuit.run(0) == f(0)) -print(circuit.run(1) == f(1)) -print(circuit.run(10) == f(10)) -print(circuit.run(60) == f(60)) +print(circuit.encrypt_run_decrypt(3) == f(3)) +print(circuit.encrypt_run_decrypt(0) == f(0)) +print(circuit.encrypt_run_decrypt(1) == f(1)) +print(circuit.encrypt_run_decrypt(10) == f(10)) +print(circuit.encrypt_run_decrypt(60) == f(60)) print("All good!") ```