The issue is with the inputset. If you add show_graph=True
argument to your mult.compile
call, you’ll see:
Computation Graph
--------------------------------------------------------------------------------
%0 = x # EncryptedScalar<uint4> ∈ [1, 9]
%1 = y # EncryptedScalar<uint3> ∈ [1, 7]
%2 = multiply(%0, %1) # EncryptedScalar<uint4> ∈ [5, 15]
return %2
--------------------------------------------------------------------------------
As you can see, your inputset resulted in at most 15 for the result, so Concrete assigned 4-bits to it. You’d need 6-bits to store 42.
When you run this circuit with 6 and 7, there is an overflow, and you get incorrect result. There are a few ways to fix it. The best option in my opinion is to increase the size of your inputset and maybe use a random one:
inputset = [
(
np.random.randint(0, 2**3, size=()),
np.random.randint(0, 2**3, size=()),
)
for _ in range(100)
]
Alternatively, you can change your implementation to:
result = x * y
fhe.hint(result, bit_width=6)
return result
or
return fhe.hint(x * y, bit_width=6)
to explicitly tell concrete you need 6-bits.
Let me know if this solves your issue