TenSEAL Documentation

repository·main·Indexed 21 days ago

https://github.com/openmined/tenseal

A library for performing homomorphic encryption operations on tensors, built on top of Microsoft SEAL. TenSEAL provides a high-level Python API for efficient encrypted computations, supporting schemes such as BFV for integers and CKKS for real numbers. It enables operations like element-wise arithmetic, dot products, matrix multiplication, and experimental 2D convolutions using im2col. The library includes a TenSEALContext for managing encryption keys and parameters, with support for automatic relinearization, rescaling, and modulus switching.

Tokens
8.4K
Snippets
29
Records
32
Agent score
76%

What's inside TenSEAL

  1. Use TenSEAL in a Bazel project

    main

    To include TenSEAL as a dependency in a Bazel workspace, add the following to your WORKSPACE file:

    load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
    
    git_repository(
       name = "org_openmined_tenseal",
       remote = "https://github.com/OpenMined/TenSEAL",
       branch = "master",
       init_submodules = True,
    )
    
    load("@org_openmined_tenseal//tenseal:preload.bzl", "tenseal_preload")
    
    tenseal_preload()
    
    load("@org_openmined_tenseal//tenseal:deps.bzl", "tenseal_deps")
    
    tenseal_deps()
  2. Use TenSEAL with Docker

    main

    You can use a pre-built Docker image for a ready-to-use environment.

    Run the latest release image:

    $ docker container run --interactive --tty openmined/tenseal

    Note: Use openmined/tenseal:dev for the image built from the master branch.

    Build a custom image:

    $ docker build -t tenseal -f docker-images/Dockerfile-py38 .

    Run your custom image:

    $ docker container run -it tenseal
  3. Build TenSEAL from source

    main

    To build TenSEAL from source, ensure you have the following requirements based on your platform:

    • Linux: GNU G++ (>= 6.0) or Clang++ (>= 5.0).
    • MacOS: Xcode toolchain (>= 9.3).
    • Windows: Microsoft Visual Studio (>= 10.0.40219.1, Visual Studio 2010 SP1 or later).

    General Steps:

    1. Install CMake (3.14 or higher).
    2. Install the Protocol Buffers compiler.
    3. Initialize and update submodules from the project root:
    $ git submodule init
    $ git submodule update

    Windows Specifics: You must build the SEAL library using Visual Studio first. Use the SEAL.sln file in third_party/SEAL to build the project native\src\SEAL.vcxproj with Configuration=Release and Platform=x64.

    Final Installation: After satisfying dependencies, run:

    $ pip install .
    $ git submodule init
    $ git submodule update
    $ pip install .
  4. Manage Ciphertext Levels during Encrypted Training

    main

    During iterative training (e.g., Stochastic Gradient Descent), the multiplicative depth of ciphertexts increases with each operation. Once the ciphertext reaches its maximum depth, you can no longer perform multiplications.

    Workaround: After each epoch, you must decrypt the model parameters (weights and bias) and re-encrypt them using the context. This resets the ciphertext level, allowing for further training iterations. In a real-world distributed setting, this involves sending the weights back to the secret-key holder for re-encryption.

    for epoch in range(EPOCHS):
        # Re-encrypt parameters to reset multiplicative depth
        eelr.encrypt(ctx_training)
    
        for enc_x, enc_y in zip(enc_x_train, enc_y_train):
            enc_out = eelr.forward(enc_x)
            eelr.backward(enc_x, enc_out, enc_y)
        
        eelr.update_parameters()
    
    # Finally decrypt to check results
    eelr.decrypt()
  5. Understand Homomorphic Encryption parameters in TenSEAL

    main

    When configuring TenSEAL for CKKS or BFV schemes, you must balance security, performance, and precision using three main parameters:

    1. Polynomial Modulus Degree (poly_modulus_degree): Must be a power of 2 (e.g., 1024, 2048, 4096, 8192, 16384, 32768).
      • Larger values: Increase security and the number of coefficients, but decrease computational performance and increase ciphertext size.
    2. Coefficient Modulus Sizes (coeff_mod_bit_sizes): A list of binary sizes used to generate primes.
      • Length of list: Determines the 'level' of the scheme (how many encrypted multiplications can be performed).
      • Larger values: Increase security but decrease performance and increase ciphertext size.
      • Constraint: Each prime must be at most 60 bits and congruent to 1 modulo $2 \times \text{poly_modulus_degree}$.
    3. Scaling Factor (CKKS only): Defines the encoding precision for real numbers. It is typically passed as a power of 2 (e.g., scale = 2 ** precision).
  6. How CKKS Relinearization and Rescaling Work

    main

    TenSEAL automates two critical CKKS operations to manage noise and ciphertext size:

    1. Relinearization: When multiplying two ciphertexts, the resulting ciphertext size grows. Relinearization reduces the size back to 2. This is required for efficient subsequent multiplications. TenSEAL performs this automatically after each encrypted multiplication using the relinearization keys.

    2. Rescaling: Homomorphic multiplications cause the approximation error (noise) to grow exponentially. Rescaling (a form of modulus-switching) scales the message down and switches the ciphertext to a smaller modulus, making the error growth linear instead of exponential. This consumes one prime from the coeff_mod_bit_sizes list. Once all primes are consumed, no further multiplications can be performed.

  7. Approximate Sigmoid using Polynomials for Encrypted Training

    main

    Standard activation functions like sigmoid cannot be computed directly on encrypted data. Instead, use a low-degree polynomial approximation.

    A degree-3 polynomial approximation for the range $[-5, 5]$ is: $$\sigma(x) = 0.5 + 0.197x - 0.004x^3$$

    In TenSEAL, you can use the .polyval() method on a ckks_vector to evaluate this polynomial. Using a lower degree is critical to minimize multiplicative depth and allow for smaller encryption parameters.

    @staticmethod
    def sigmoid(enc_x):
        # We use the polynomial approximation of degree 3
        # sigmoid(x) = 0.5 + 0.197 * x - 0.004 * x^3
        return enc_x.polyval([0.5, 0.197, 0, -0.004])
  8. Manage context privacy and secret keys

    main

    By default, a TenSEALContext is 'private', meaning it holds the secret key and can be used for decryption. You can convert a context to 'public' using .make_context_public(), which drops the secret key. This is useful when you want to send the context to a remote worker to perform computations without giving them the ability to decrypt the results.

    Use .is_private() and .is_public() to check the current state of the context.

    public_context = ts.context(ts.SCHEME_TYPE.BFV, poly_modulus_degree=4096, plain_modulus=1032193)
    
    # Check status
    print("Is private?", public_context.is_private())
    
    # Drop the secret key to make it public
    public_context.make_context_public()
    print("Is public?", public_context.is_public())
  9. Evaluate ciphertext precision in CKKS

    main

    In the CKKS scheme, precision is impacted by the relationship between the input data range, the scaling factor, and the coefficient modulus sizes.

    When performing operations like addition or multiplication, the available precision (the power of 2 by which you can approximate the result) may decrease. If the input values are too large relative to the chosen parameters, encryption or subsequent operations may fail.

  10. Perform 2D convolution on encrypted data using im2col

    main

    TenSEAL provides an experimental way to perform 2D convolutions on encrypted data using the im2col (Image Block to Column) approach.

    To perform a 2D convolution:

    1. Encode and Encrypt: Use ts.im2col_encoding to transform the input image into an encrypted format suitable for convolution. This function returns an encrypted vector and the number of windows produced.
    2. Compute Convolution: Use the .conv2d_im2col() method on the resulting encrypted vector. This method takes the kernel (as a list) and the number of windows as arguments.
    3. Decrypt: Decrypt the resulting ciphertext to retrieve the plain text convolution result.

    Note on Workflow: For multi-layer convolutions, a client-server communication pattern is required. The server sends the ciphertext to the client, the client decrypts it and applies im2col to the plaintext, then re-encrypts the data to send back to the server for the next layer.

    # 1. Encode and encrypt the input image
    x_enc, windows_nb = ts.im2col_encoding(context, x, kernel.shape[0], kernel.shape[1], stride)
    
    # 2. Perform the convolution on the ciphertext
    y_enc = x_enc.conv2d_im2col(kernel.tolist(), windows_nb)
    
    # 3. Decrypt the result
    y_plain = y_enc.decrypt()
  11. Configure TenSEAL context for CKKS convolution

    main

    To perform encrypted convolutions, you must initialize a TenSEAL context using the CKKS scheme. You need to specify the polynomial modulus degree, coefficient modulus bit sizes, and a global scale. Additionally, you must generate Galois keys to enable rotations on ciphertext vectors.

    Required configuration steps:

    • Use ts.SCHEME_TYPE.CKKS.
    • Set context.global_scale (e.g., pow(2, 40)).
    • Call context.generate_galois_keys() to support rotations.
    import tenseal as ts
    
    # Create TenSEAL context
    context = ts.context(
        ts.SCHEME_TYPE.CKKS, 8192, coeff_mod_bit_sizes=[60, 40, 40, 60]
    )
    
    # Set the scale
    context.global_scale = pow(2, 40)
    
    # Generate galois keys in order to do rotation on ciphertext vectors
    context.generate_galois_keys()