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
Let me know if you have any other questions.
Umut