Skip to content

Commit

Permalink
Updated examples for autoexample generation in docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ibarrond committed Feb 10, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 539e6d4 commit e244230
Showing 12 changed files with 66 additions and 24 deletions.
19 changes: 14 additions & 5 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
include Pyfhel/*.pxd
include Pyfhel/*.pyx
# Include all cython source files
global-include *.pyx *.pxd

# Include python packages
include Pyfhel/*.py
include Pyfhel/utils/**

# Exclude the cython generated cpp files, as they depend on the numpy version
exclude Pyfhel/*.cpp

# Include all Afhel source files and headers
include Pyfhel/Afhel/*.cpp
include Pyfhel/Afhel/*.h
include Pyfhel/Afhel/*.pxd

# Include backend sources
global-include Pyfhel/backend/SEAL/**
global-exclude Pyfhel/backend/palisade/**
global-include *.pyx *.pxd *.h

include docs/static/*

# Include examples
include examples/*.py

# Include standard project files
include docs/static/*
include README.md
include LICENSE.txt
include setup.py
8 changes: 4 additions & 4 deletions Pyfhel/Afhel/Afseal.cpp
Original file line number Diff line number Diff line change
@@ -101,9 +101,9 @@ string Afseal::ContextGen(scheme_t scheme,
{
parms.set_coeff_modulus(CoeffModulus::Create(poly_modulus_degree, qi_sizes));
}
else if ((scheme == scheme_t::bfv) && (sec > 0))
else if (((scheme == scheme_t::bfv) || (scheme == scheme_t::bgv)) && (sec > 0))
{
parms.set_coeff_modulus( // BFV: Select from seal/utils/globals.cpp
parms.set_coeff_modulus( // BFV/BGV: Select from seal/utils/globals.cpp
CoeffModulus::BFVDefault(poly_modulus_degree, sec_map[sec]));
}
else
@@ -116,8 +116,8 @@ string Afseal::ContextGen(scheme_t scheme,
{
this->qi.emplace_back(modulus.value());
}
// Setting t --> BFV only
if (scheme == scheme_t::bfv)
// Setting t --> BFV and BGV only
if ((scheme == scheme_t::bfv) || (scheme == scheme_t::bgv))
{
if(plain_modulus_bit_size > 0) // Auto sel.
{
2 changes: 1 addition & 1 deletion Pyfhel/__init__.py
Original file line number Diff line number Diff line change
@@ -7,4 +7,4 @@
__name__ = "Pyfhel"
__author__ = "Alberto Ibarrondo"

__version__ = "3.4.0"
__version__ = "3.4.1"
3 changes: 3 additions & 0 deletions Pyfhel/test/test_Demos.py
Original file line number Diff line number Diff line change
@@ -58,5 +58,8 @@ def test_Demo_7_ScalarProd():
def test_Demo_8_HammingDist():
execfile(EXAMPLES_FOLDER / 'Demo_8_HammingDist.py')

def test_Demo_9_Integer_BGV():
execfile(EXAMPLES_FOLDER / 'Demo_9_Integer_BGV.py')

def test_Demo_WAHC21():
execfile(EXAMPLES_FOLDER / 'Demo_WAHC21.py')
15 changes: 15 additions & 0 deletions Pyfhel/test/test_Pyfhel.py
Original file line number Diff line number Diff line change
@@ -101,6 +101,8 @@ def test_Pyfhel_encrypt(self, HE_ckks):
HE_ckks.encryptAComplex(np.array([[1+1j,1j],[1-1j,1]]))
with pytest.raises(NotImplementedError, match=".*<Pyfhel ERROR>.*"):
HE_ckks.encryptAPtxt(np.array([PyPtxt(), PyPtxt()], dtype=object))
with pytest.raises(NotImplementedError, match=".*<Pyfhel ERROR>.*"):
HE_ckks.encryptABGV(np.array([[1,1],[1,1]],dtype=np.int64))
with pytest.raises(TypeError, match=".*<Pyfhel ERROR>.*"):
HE_ckks.encrypt("wrong type")

@@ -113,6 +115,8 @@ def test_Pyfhel_decrypt(self, HE_ckks):
HE_ckks.decryptFrac(c2)
with pytest.raises(RuntimeError, match=".*wrong scheme.*"):
HE_ckks.decryptComplex(c2)
with pytest.raises(RuntimeError, match=".*wrong scheme.*"):
HE_ckks.decryptBGV(c2)
# vectorized
with pytest.raises(NotImplementedError, match=".*not implemented.*"):
HE_ckks.decryptAInt(c)
@@ -122,6 +126,8 @@ def test_Pyfhel_decrypt(self, HE_ckks):
HE_ckks.decryptAComplex(c)
with pytest.raises(NotImplementedError, match=".*not implemented.*"):
HE_ckks.decryptAPtxt(c)
with pytest.raises(NotImplementedError, match=".*not implemented.*"):
HE_ckks.decryptABGV(c)
# full decode
with pytest.raises(RuntimeError, match=".*wrong scheme.*"):
c3 = PyCtxt()
@@ -135,6 +141,8 @@ def test_Pyfhel_encode(self, HE_ckks, HE_bfv):
HE_ckks.encodeAFrac(np.array([[1.]],dtype=np.float64))
with pytest.raises(NotImplementedError, match=".*<Pyfhel ERROR>.*"):
HE_ckks.encodeAComplex(np.array([[1+1j]]))
with pytest.raises(NotImplementedError, match=".*<Pyfhel ERROR>.*"):
HE_bfv.encodeABGV(np.array([[1]],dtype=np.int64))

# 3d arrays not supported
with pytest.raises(TypeError, match=".*<Pyfhel ERROR>.*"):
@@ -148,6 +156,9 @@ def test_Pyfhel_encode(self, HE_ckks, HE_bfv):
HE_ckks.encode(np.array([[1.]],dtype=np.float64))
with pytest.raises(NotImplementedError, match=".*encryptAComplex not implemented.*"):
HE_ckks.encode(np.array([[1+1j]]))
with pytest.raises(TypeError, match=".*Plaintext could not be encoded.*"):
HE_bgv = Pyfhel(context_params={'scheme':'BGV', 'n': 2**13, 't': 65537, 't_bits': 20, 'sec': 128,})
HE_bgv.encode(np.array([[1,2]]))

def test_Pyfhel_decode(self, HE_ckks, HE_bfv):
p = HE_ckks.encode(1)
@@ -158,6 +169,8 @@ def test_Pyfhel_decode(self, HE_ckks, HE_bfv):
HE_bfv.decodeFrac(p)
with pytest.raises(RuntimeError, match=".*scheme must be ckks.*"):
HE_bfv.decodeComplex(p)
with pytest.raises(RuntimeError, match=".*scheme must be bgv.*"):
HE_bfv.decodeBGV(p)
# Vectorized
p_v = np.array([p],dtype=object)
with pytest.raises(NotImplementedError, match=".*<Pyfhel ERROR>.*"):
@@ -166,6 +179,8 @@ def test_Pyfhel_decode(self, HE_ckks, HE_bfv):
HE_ckks.decodeAFrac(p_v)
with pytest.raises(NotImplementedError, match=".*<Pyfhel ERROR>.*"):
HE_ckks.decodeAComplex(p_v)
with pytest.raises(NotImplementedError, match=".*<Pyfhel ERROR>.*"):
HE_ckks.decodeAComplex(p_v)

# scheme none
del p.scheme
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@

**Pyfhel**: **PY**thon **F**or **H**omomorphic **E**ncryption **L**ibraries.

* **_Version_**: 3.4.0
* **_Version_**: 3.4.1
* **_Status_**: STABLE
* **_Description_**: Allows ADDITION, SUBSTRACTION, MULTIPLICATION, SCALAR PRODUCT over encrypted integers (BFV) and approximated floating point values (CKKS . This library acts as optimized Python API for the most advanced C++ HE libraries.
* **_Language_**: Python (3.7+) & Cython on top of C++17.
7 changes: 5 additions & 2 deletions examples/Demo_2_Integer_BFV.py
Original file line number Diff line number Diff line change
@@ -16,10 +16,13 @@
# Ideally, one should use as little `n` and `t` as possible while keeping the
# correctness in the operations.
# The noise budget in a freshly encrypted ciphertext is
# ~ log2(coeff_modulus/plain_modulus) (bits)
#
# ~ log2(coeff_modulus/plain_modulus) (bits)
#
# By far the most demanding operation is the homomorphic (ciphertext-ciphertext)
# multiplication, consuming a noise budget of around:
# log2(plain_modulus) + (other terms).
#
# log2(plain_modulus) + (other terms).

HE = Pyfhel() # Creating empty Pyfhel object
bfv_params = {
2 changes: 1 addition & 1 deletion examples/Demo_7_ScalarProd.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
# %%
# A1. Vector Generation
# ---------------------------
# We will define a pair of 1D integer vectors of size l and elementsize <= |v_max|.
# We will define a pair of 1D integer vectors of size l and elementsize <= ``|v_max|``.
# For the purpose of this demo, we can study three cases:
# #1: small l (l <= n) and high v_max. --> encoding with trailing zeros
# #2: fitting l (l = n) and medium v_max. --> fits the encoding perfectly
3 changes: 2 additions & 1 deletion examples/Demo_8_HammingDist.py
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
We will translate the hamming distance into a scalar product by translating the
XOR op. to the arithmetic domain:
xor(x,y) = (x-y)^2 = x + y - 2*(x*y)
HD(x,y) = sum (x[i] xor y[i]) = sum(x[i]) + sum(y[i]) - 2*sum(x[i]*y[i])
@@ -51,7 +52,7 @@


# %%
# 2. Context and key setup
# 2. Hamming Distance setup
# ---------------------------
# Parameter selection goes according to vector length and max element size.
from Pyfhel import Pyfhel
20 changes: 13 additions & 7 deletions examples/Demo_9_Integer_BGV.py
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@


# %%
# 3. Integer Encryption
# 3. BGV Integer Encryption
# ---------------------------
# we will define two integers and encrypt them using `encryptBGV`:
integer1 = np.array([127], dtype=np.int64)
@@ -63,8 +63,8 @@
print(ctxt2)

# %%
# 4. Operating with encrypted integers
# --------------------------------------
# 4. Operating with encrypted integers in BGV
# ---------------------------------------------
# Relying on the context defined before, we will now operate
# (addition, substaction, multiplication) the two ciphertexts:
ctxtSum = ctxt1 + ctxt2 # `ctxt1 += ctxt2` for inplace operation
@@ -76,13 +76,14 @@
print(f"Mult:{ctxtMul}")

# %%
# 5. Decrypting integers
# ---------------------------
# 5. Decrypting BGV integers
# ------------------------------
# Once we're finished with the encrypted operations, we can use
# the Pyfhel instance to decrypt the results using `decryptBGV`:
resSum = HE.decryptBGV(ctxtSum) # Decryption must use the corresponding function
# decryptBGV.
resSub = HE.decryptBGV(ctxtSub)
resSub = HE.decrypt(ctxtSub) # `decrypt` function detects the scheme and
# calls the corresponding decryption function.
resMul = HE.decryptBGV(ctxtMul)
print("\n5. Decrypting result:")
print(" addition: decrypt(ctxt1 + ctxt2) = ", resSum)
@@ -101,7 +102,12 @@
arr2 = np.array([-bgv_params['t']//2, -1, 1], dtype=np.int64) # Min possible value is -t/2.

ptxt1 = HE.encodeBGV(arr1) # Creates a PyPtxt plaintext with the encoded arr1
ptxt2 = HE.encodeBGV(arr2) # plaintexts created from arrays shorter than 'n' are filled with zeros.
# plaintexts created from arrays shorter than 'n' are filled with zeros.
ptxt2 = HE.encode(arr2) # `encode` function detects the scheme and calls the
# corresponding encoding function.

assert np.allclose(HE.decodeBGV(ptxt1), arr1) # Decoding the encoded array should return the original array
assert np.allclose(HE.decode(ptxt2)[:3], arr2) # `decode` function detects the scheme

ctxt1 = HE.encryptPtxt(ptxt1) # Encrypts the plaintext ptxt1 and returns a PyCtxt
ctxt2 = HE.encryptPtxt(ptxt2) # Alternatively you can use HE.encryptInt(arr2)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
# Pyfhel's core metadata
[project]
name = "Pyfhel"
version = "3.4.0"
version = "3.4.1"
description = "Python for Homomorphic Encryption Libraries"
readme = "README.md"
requires-python = ">=3.7"
7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -108,6 +108,11 @@ def _path(args: List[str], base_dir=None) -> List[Path]:
base_dir = Path('') if base_dir is None else base_dir
return [(base_dir/arg).absolute().as_posix() if isinstance(arg, (str, Path)) else arg for arg in args]

def _npath(args: List[str], base_dir=None) -> List[Path]:
"""_npath: Normalizes path separations with is.path.normpath. Does not generate absolute paths"""
base_dir = Path('') if base_dir is None else base_dir
return [os.path.normpath((base_dir/arg).as_posix()) if isinstance(arg, (str, Path)) else arg for arg in args]

def _tupl(args: List[List[str]]) -> List[Tuple[str, str]]:
"""_tupl: Picks elements and turns them into tuples"""
return [tuple(arg) for arg in args]
@@ -628,7 +633,7 @@ def copy_extensions_to_source(self):
for ext_name, ext_conf in extensions.items():
ext_modules.append(Extension(
name = ext_conf.pop('fullname', f"{project_name}.{ext_name}"),
sources = (_pl(ext_conf.pop('sources', []))),
sources =_npath(_pl(ext_conf.pop('sources', []))),
include_dirs = _path(_pl(ext_conf.pop('include_dirs', []))) + include_dirs,
define_macros = _tupl(_pl(ext_conf.pop('include_dirs', []))) + define_macros,
language = "c++",

0 comments on commit e244230

Please sign in to comment.