Files
concrete/frontends/concrete-python/tests/execution/test_bitwise.py

148 lines
3.9 KiB
Python

"""
Tests of execution of bitwise operations.
"""
import random
from typing import Callable, List, Optional, Tuple
import numpy as np
import pytest
from concrete import fhe
from concrete.fhe.dtypes import Integer
from concrete.fhe.values import ValueDescription
operations = [
("&", lambda x, y: x & y),
("|", lambda x, y: x | y),
("^", lambda x, y: x ^ y),
]
cases: List[
Tuple[
Tuple[str, Callable],
int,
int,
Tuple[int, ...],
Tuple[int, ...],
Optional[fhe.BitwiseStrategy],
]
] = []
for lhs_bitwidth in range(1, 6):
for rhs_bitwidth in range(1, 6):
cases += [
(
# operation
operations[0],
# bit widths
lhs_bitwidth,
rhs_bitwidth,
# shapes
(),
(),
# strategy
None,
)
]
cases += [
(
operation,
# bit widths
random.choice([1, 2, 3, 4, 5]),
random.choice([1, 2, 3, 4, 5]),
# shapes
random.choice([(), (2,), (3, 2)]),
random.choice([(), (2,), (3, 2)]),
# strategy
random.choice(
[
fhe.BitwiseStrategy.ONE_TLU_PROMOTED,
fhe.BitwiseStrategy.THREE_TLU_CASTED,
fhe.BitwiseStrategy.TWO_TLU_BIGGER_PROMOTED_SMALLER_CASTED,
fhe.BitwiseStrategy.TWO_TLU_BIGGER_CASTED_SMALLER_PROMOTED,
]
),
)
for operation in operations
for _ in range(10)
]
@pytest.mark.parametrize(
"operation,lhs_bit_width,rhs_bit_width,lhs_shape,rhs_shape,strategy",
cases,
)
def test_bitwise(
operation,
lhs_bit_width,
rhs_bit_width,
lhs_shape,
rhs_shape,
strategy,
helpers,
):
"""
Test bitwise operations between encrypted integers.
"""
name, function = operation
lhs_dtype = Integer(is_signed=False, bit_width=lhs_bit_width)
rhs_dtype = Integer(is_signed=False, bit_width=rhs_bit_width)
lhs_description = ValueDescription(lhs_dtype, shape=lhs_shape, is_encrypted=True)
rhs_description = ValueDescription(rhs_dtype, shape=rhs_shape, is_encrypted=True)
print()
print()
print(
f"[{lhs_description}] ({name}) [{rhs_description}]"
+ (f" {{{strategy}}}" if strategy is not None else "")
)
print()
print()
parameter_encryption_statuses = {"x": "encrypted", "y": "encrypted"}
configuration = helpers.configuration().fork(use_insecure_key_cache=False)
if strategy is not None:
configuration = configuration.fork(bitwise_strategy_preference=[strategy])
compiler = fhe.Compiler(function, parameter_encryption_statuses)
inputset = [
(
np.random.randint(lhs_dtype.min(), lhs_dtype.max() + 1, size=lhs_shape),
np.random.randint(rhs_dtype.min(), rhs_dtype.max() + 1, size=rhs_shape),
)
for _ in range(100)
]
circuit = compiler.compile(inputset, configuration)
samples = [
[
np.zeros(lhs_shape, dtype=np.int64),
np.zeros(rhs_shape, dtype=np.int64),
],
[
np.ones(lhs_shape, dtype=np.int64) * lhs_dtype.min(),
np.ones(rhs_shape, dtype=np.int64) * rhs_dtype.min(),
],
[
np.ones(lhs_shape, dtype=np.int64) * lhs_dtype.max(),
np.ones(rhs_shape, dtype=np.int64) * rhs_dtype.min(),
],
[
np.ones(lhs_shape, dtype=np.int64) * lhs_dtype.max(),
np.ones(rhs_shape, dtype=np.int64) * rhs_dtype.max(),
],
[
np.random.randint(lhs_dtype.min(), lhs_dtype.max() + 1, size=lhs_shape),
np.random.randint(rhs_dtype.min(), rhs_dtype.max() + 1, size=rhs_shape),
],
]
for sample in samples:
helpers.check_execution(circuit, function, sample, retries=5)