OpenFHE-Numpy documentation for power says that it performs “element-wise power.” However, onp.power performs a series of matrix multiplications instead. Minimum reproducible code:
import numpy as np
from openfhe import *
import openfhe_numpy as onp
np.set_printoptions(precision=3)
MATRIX_SIZE = 4
batch_size = MATRIX_SIZE * MATRIX_SIZE
scale_mod_size = 30
first_mod_size = 32
params = CCParamsCKKSRNS()
params.SetScalingModSize(scale_mod_size)
params.SetFirstModSize(first_mod_size)
params.SetMultiplicativeDepth(8)
params.SetBatchSize(batch_size)
params.SetScalingTechnique(FIXEDAUTO)
params.SetKeySwitchTechnique(HYBRID)
cc = GenCryptoContext(params)
cc.Enable(PKESchemeFeature.PKE)
cc.Enable(PKESchemeFeature.LEVELEDSHE)
cc.Enable(PKESchemeFeature.ADVANCEDSHE)
keys = cc.KeyGen()
cc.EvalMultKeyGen(keys.secretKey)
cc.EvalSumKeyGen(keys.secretKey)
onp.EvalSquareMatMultRotateKeyGen(keys.secretKey, MATRIX_SIZE)
ring_dim = cc.GetRingDimension()
batch_size = cc.GetBatchSize()
print("Context and keys initialized.")
print("CKKS ring dimension:", ring_dim)
print("Available slots:", batch_size)
print("Multiplication Depth:", cc.GetMultiplicativeDepth())
A = np.array([[1, 2], [3, 4]])
encrypted = onp.array(
cc=cc,
data=A,
batch_size=batch_size,
order=onp.ROW_MAJOR,
fhe_type="C",
public_key=keys.publicKey,
)
print("Starting matrix A:")
print(A)
print("Intended operation: A ** 3")
original_op = onp.pow(encrypted, 3)
decrypted = original_op.decrypt(keys.secretKey, unpack_type="original")
print("Decrypted result of power operation:")
print(decrypted)
print("Expected result:")
print(A ** 3)
Output:
Context and keys initialized.
CKKS ring dimension: 16384
Available slots: 16
Multiplication Depth: 8
Starting matrix A:
[[1 2]
[3 4]]
Intended operation: A ** 3
Decrypted result of power operation:
[[ 36.959 53.955]
[ 80.934 117.872]]
Expected result:
[[ 1 8]
[27 64]]