In Concrete v1, there were PublicArguments and PublicResult types. PublicArguments was used to encapsulate encrypted and clear arguments to the function and PublicResult was used to store the encrypted result of the function.
x, y, z = 10, 20, 30
encrypted_args = circuit.encrypt(x, y, z)
encrypted_result = circuit.run(encrypted_args)
result = circuit.decrypt(encrypted_result)where encrypted_args is of type fhe.PublicArguments, and encrypted_result is of type fhe.PublicResult.
This was simple, but limiting (e.g., since PublicArguments contained all arguments, a change in one of the arguments required re-encryption of all arguments).
In Concrete v2, there is fhe.Value type, which is the result of all of encrypt, run, and decrypt.
x, y, z = 10, 20, 30
encrypted_x, encrypted_y, encrypted_z = circuit.encrypt(x, y, z)
encrypted_result = circuit.run(encrypted_x, encrypted_y, encrypted_z)
result = circuit.decrypt(encrypted_result)where all of encrypted_x, encrypted_y, encrypted_z and encrypted_result are fhe.Value.
In case y value needs to be changed whereas the others need to remain, it's possible to do:
new_y = 42
_, new_encrypted_y, _ = circuit.encrypt(None, new_y, None)
new_encrypted_result = circuit.run(encrypted_x, new_encrypted_y, encrypted_z)
new_result = circuit.decrypt(new_encrypted_result)New fhe.Circuit.run(...) also support tuples so the old code still works! However, fhe.Server.run(...) had another parameter called evaluation_keys, which have to be a keyword argument now as function arguments are variadic now!
server: fhe.Server = ...
encrypted_x: fhe.Value = ...
encrypted_y: fhe.Value = ...
encrypted_z: fhe.Value = ...
evaluation_keys: fhe.EvaluationKeys = ...
server.run(encrypted_x, encrypted_y, encrypted_z, evaluation_keys=evaluation_keys)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
this needs to be a keyword argument nowWhereas previously it could be:
server: fhe.Server = ...
encrypted_args: fhe.PublicArguments = ...
evaluation_keys: fhe.EvaluationKeys = ...
server.run(encrypted_args, evaluation_keys)from concrete import fheinstead of the previous:
import concrete.numpy as cnpfrom concrete import fhe
fhe.conv(...)
fhe.maxpool(...)instead of the previous:
from concrete.onnx import connx
connx.conv(...)
connx.maxpool(...)Virtual configuration option is removed. Simulation is still supported using the new simulate method on circuits:
from concrete import fhe
@fhe.compiler({"x": "encrypted"})
def f(x):
return x + 42
inputset = range(10)
circuit = f.compile(inputset)
assert circuit.simulate(1) == 43instead of the previous:
import concrete.numpy as cnp
@cnp.compiler({"x": "encrypted"})
def f(x):
return x + 42
inputset = range(10)
circuit = f.compile(inputset, enable_unsafe_features=True, virtual=True)
assert circuit.encrypt_run_decrypt(1) == 43