Implementation of boolean operator

Hi,
I’m trying to play around with concrete_numpy and I don’t understand how to use boolean operators.
This page (Compatibility - Concrete Numpy) is listing the and and or Python operator, yet when I try to run this example :

import concrete.numpy as cnp

def or_homomorphic(x, y):
    return x or y


compiler = cnp.Compiler(or_homomorphic, {"x": "encrypted", "y": "encrypted"})

inputset = [(1, 1), (0, 0), (1, 0), (0, 1)]
circuit = compiler.compile(inputset)

x = 0
y = 0

clear_evaluation = or_homomorphic(x, y)
homomorphic_evaluation = circuit.encrypt_run_decrypt(x, y)

print(x, " or ", y, " = ", clear_evaluation, "=", homomorphic_evaluation)

I get this error :

I guess I’m doing something wrong here, but I don’t understand what.
Thank you for your help

Hi @nbon,

The documentation mentions __and__ and __or__ methods, which correspond to & and ^ operators, not and and or operators (see 3. Data model — Python 3.11.1 documentation).

Also, those are only supported between an encrypted value and a constant for the time being. For example, you can do:

import concrete.numpy as cnp
import numpy as np

@cnp.compiler({"x": "encrypted"})
def f(x):
    return x & 0b_0000_0001

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

for i in inputset:
    if circuit.encrypt_run_decrypt(i):
        print(i, "is odd")
    else:
        print(i, "is even")

or apply all kinds of masks to extract bits from the inputs.

We are aware that bitwise operators between encrypted values are highly important and we have an open bounty to support those (see bounty-program/Bounties/Engineering at main · zama-ai/bounty-program · GitHub), so they will become available in the near future.

Lastly, I might offer a workaround for the time being:

import concrete.numpy as cnp
import numpy as np

or_table = cnp.LookupTable([0, 1, 1])

def or_bits(x, y):
    return or_table[x + y]

@cnp.compiler({"x": "encrypted", "y": "encrypted"})
def f(x, y):
    return or_bits(x, y)

inputset = [(1, 1), (0, 0), (1, 0), (0, 1)]
circuit = f.compile(inputset)

for input in inputset:
    print(input[0], "|", input[1], "==", circuit.encrypt_run_decrypt(*input))

# This works by adding x and y to get:
# |------------------|
# | x | y | addition |
# |------------------|
# | 0 | 0 | 0        |
# | 0 | 1 | 1        |
# | 1 | 0 | 1        |
# | 1 | 1 | 2        |
# |------------------|

# And then applying a table lookup to this addition using the table [0, 1, 1], which results in:
# 0 if addition is 0
# 1 if addition is either 1 or 2

You can apply a similar technique for & operation as well. Just keep in mind that this will result in 2-bit integers, which is okay, it’s just something to keep in mind.

Hope this helps :slight_smile:

Let me know if you have any other questions.
Umut

1 Like

Thank you very much for this super clear answer.

2 Likes