Concrete
WebsiteLibrariesProducts & ServicesDevelopersSupport
2.7
2.7
  • Welcome
  • Get Started
    • What is Concrete?
    • Installation
    • Quick start
    • Compatibility
    • Terminology
  • Core features
    • Overview
    • Table lookups (basics)
    • Non-linear operations
    • Advanced features
      • Bit extraction
      • Common tips
      • Extensions
  • Compilation
    • Combining compiled functions
      • With composition
      • With modules
    • Key-related options for faster execution
      • Multi precision
      • Multi parameters
    • Compression
    • Reusing arguments
    • Common errors
  • Execution / Analysis
    • Simulation
    • Debugging and artifact
    • GPU acceleration
    • Other
      • Statistics
      • Progressbar
      • Formatting and drawing
  • Guides
    • Configure
    • Manage keys
    • Deploy
  • Tutorials
    • See all tutorials
    • Part I: Concrete - FHE compiler
    • Part II: The Architecture of Concrete
  • References
    • API
  • Explanations
    • Compiler workflow
    • Compiler internals
      • Table lookups
      • Rounding
      • Truncating
      • Floating points
      • Comparisons
      • Min/Max operations
      • Bitwise operations
      • Direct circuits
      • Tagging
    • Security
    • Frontend fusing
  • Developers
    • Contributing
    • Release note
    • Feature request
    • Bug report
    • Project layout
    • Compiler backend
      • Adding a new backend
    • Optimizer
    • MLIR FHE dialects
      • FHELinalg dialect
      • FHE dialect
      • TFHE dialect
      • Concrete dialect
      • Tracing dialect
      • Runtime dialect
      • SDFG dialect
    • Call FHE circuits from other languages
Powered by GitBook

Libraries

  • TFHE-rs
  • Concrete
  • Concrete ML
  • fhEVM

Developers

  • Blog
  • Documentation
  • Github
  • FHE resources

Company

  • About
  • Introduction to FHE
  • Media
  • Careers
On this page
  • Deploy
  • Development of the circuit
  • Setting up a server
  • Setting up clients
  • Generating keys (on the client)
  • Encrypting inputs (on the client)
  • Performing computation (on the server)
  • Decrypting the result (on the client)
  • Deployment of modules

Was this helpful?

Export as PDF
  1. Guides

Deploy

Deploy

After developing your circuit, you may want to deploy it. However, sharing the details of your circuit with every client might not be desirable. As well as this, you might want to perform the computation on dedicated servers. In this case, you can use the Client and Server features of Concrete.

Development of the circuit

You can develop your circuit using the techniques discussed in previous chapters. Here is a simple example:

from concrete import fhe

@fhe.compiler({"x": "encrypted"})
def function(x):
    return x + 42

inputset = range(10)
circuit = function.compile(inputset)

Once you have your circuit, you can save everything the server needs:

circuit.server.save("server.zip")

Then, send server.zip to your computation server.

Setting up a server

You can load the server.zip you get from the development machine:

from concrete import fhe

server = fhe.Server.load("server.zip")

You will need to wait for requests from clients. The first likely request is for ClientSpecs.

Clients need ClientSpecs to generate keys and request computation. You can serialize ClientSpecs:

serialized_client_specs: str = server.client_specs.serialize()

Then, you can send it to the clients requesting it.

Setting up clients

After getting the serialized ClientSpecs from a server, you can create the client object:

client_specs = fhe.ClientSpecs.deserialize(serialized_client_specs)
client = fhe.Client(client_specs)

Generating keys (on the client)

Once you have the Client object, you can perform key generation:

client.keys.generate()

This method generates encryption/decryption keys and evaluation keys.

The server needs access to the evaluation keys that were just generated. You can serialize your evaluation keys as shown:

serialized_evaluation_keys: bytes = client.evaluation_keys.serialize()

After serialization, send the evaluation keys to the server.

Serialized evaluation keys are very large, so you may want to cache them on the server instead of sending them with each request.

Encrypting inputs (on the client)

The next step is to encrypt your inputs and request the server to perform some computation. This can be done in the following way:

arg: fhe.Value = client.encrypt(7)
serialized_arg: bytes = arg.serialize()

Then, send the serialized arguments to the server.

Performing computation (on the server)

Once you have serialized evaluation keys and serialized arguments, you can deserialize them:

deserialized_evaluation_keys = fhe.EvaluationKeys.deserialize(serialized_evaluation_keys)
deserialized_arg = fhe.Value.deserialize(serialized_arg)

You can perform the computation, as well:

result: fhe.Value = server.run(deserialized_arg, evaluation_keys=deserialized_evaluation_keys)
serialized_result: bytes = result.serialize()

Then, send the serialized result back to the client. After this, the client can decrypt to receive the result of the computation.

Decrypting the result (on the client)

Once you have received the serialized result of the computation from the server, you can deserialize it:

deserialized_result = fhe.Value.deserialize(serialized_result)

Then, decrypt the result:

decrypted_result = client.decrypt(deserialized_result)
assert decrypted_result == 49

Deployment of modules

from concrete import fhe

@fhe.module()
class MyModule:
    @fhe.function({"x": "encrypted"})
    def inc(x):
        return x + 1

    @fhe.function({"x": "encrypted"})
    def dec(x):
        return x - 1

inputset = list(range(20))
my_module = MyModule.compile({"inc": inputset, "dec": inputset})
)

You can extract the server from the module and save it in a file:

my_module.server.save("server.zip")

The only noticeable difference between the deployment of modules and the deployment of circuits is that the methods Client::encrypt, Client::decrypt and Server::run must contain an extra function_name argument specifying the name of the targeted function.

The encryption of an argument for the inc function of the module would be:

arg = client.encrypt(7, function_name="inc")
serialized_arg = arg.serialize()

The execution of the inc function would be :

result = server.run(deserialized_arg, evaluation_keys=deserialized_evaluation_keys, function_name="inc")
serialized_result = result.serialize()

Finally, decrypting a result from the execution of dec would be:

decrypted_result = client.decrypt(deserialized_result, function_name="dec")
PreviousManage keysNextSee all tutorials

Last updated 10 months ago

Was this helpful?

Deploying a follows the same logic as the deployment of circuits. Assuming a module compiled in the following way:

module