Beispiel #1
0
 def binop_test(self, binop):
     for i in range(ITERATIONS):
         a = self.rand()
         b = self.rand()
         self.assertAlmostEqual(decrypt(binop(encrypt(a), encrypt(b))),
                                binop(a, b),
                                places=3)
Beispiel #2
0
    def __init__(self, value):
        if isinstance(value, EncryptedValue): value = value._ciphertext
        if not isinstance(value, Ciphertext):
            value = simplefhe.encrypt(value)._ciphertext

        self._ciphertext = value
        self._mode = simplefhe._mode
Beispiel #3
0
 def test_running_sum(self):
     true = 0
     target = 0
     for i in range(ITERATIONS):
         x = self.rand()
         true += x
         target += encrypt(x)
     self.assertAlmostEqual(decrypt(target), true, places=3)
Beispiel #4
0
def smart_product(values: List[EncryptedValue]) -> EncryptedValue:
    if not values: return simplefhe.encrypt(1)
    if len(values) == 1: return values[0]

    new = []
    for i in range(len(values) // 2):
        new.append(values[2 * i] * values[2 * i + 1])
    if len(values) % 2 == 1:
        new.append(values[-1])
    return smart_product(new)
Beispiel #5
0
    def _binop(self,
               other,
               cipher_func,
               plain_func=None,
               _is_mult: bool = False):
        """
        Returns the result of a binary operation between self and other.
        
        :param cipher_func:
            Must take three Ciphertext arguments.
            The function must apply a binary operation to the
            first two arguments, and overwrite the third argument
            with the result.

        :param plain_func:
            Optional. Used when `other` is an unencrypted value
            for performance improvement.
            If omitted, `other` will be encrypted and passed into
            `cipher_func`.
        """
        result = Ciphertext()
        if isinstance(other, EncryptedValue):
            other = other._ciphertext

        # Must normalize floats to same scale before adding/subtracting
        evaluator = simplefhe._evaluator

        # If adding, we need to match scale and modulus
        if self._is_float:
            target_scale = simplefhe._mode['default_scale']
            if not _is_mult:
                self._ciphertext.scale(target_scale)

            parms = self._ciphertext.parms_id()

            def normalize(x, p=parms):
                simplefhe._evaluator.mod_switch_to_inplace(x, p)

        # After each multiplication, we should relinearize
        def renormalize(x):
            if _is_mult:
                evaluator.relinearize_inplace(x, simplefhe._relin_keys)
                if self._is_float:
                    evaluator.rescale_to_next_inplace(x)

            # Determine type of other operand

        if not isinstance(other, Ciphertext):
            from simplefhe.encryptors import encode_item
            if plain_func is not None:
                # Use plain_func for performance
                pt = encode_item(other)
                if self._is_float: normalize(pt)
                plain_func(self._ciphertext, pt, result)
                renormalize(result)
                return EncryptedValue(result)
            else:
                # Fallback to encrypting and using cipher_func
                other = simplefhe.encrypt(other)._ciphertext

        # If adding, we need to match scale and modulus
        #if self._is_float and not _is_mult:
        if self._is_float:
            other.scale(target_scale)
            try:
                normalize(other)
            except:
                self._ciphertext.scale(target_scale)
                normalize(self._ciphertext, p=other.parms_id())

        # Compute binary operation
        cipher_func(self._ciphertext, other, result)

        renormalize(result)
        return EncryptedValue(result)
Beispiel #6
0
    generate_keypair,
    set_public_key, set_private_key, set_relin_keys,
    display_config
)

# In a real application, the keypair would be generated once,
# and only the public key would be provided to the server.
# A more realistic example is given later.
display_config()
public_key, private_key, relin_keys = generate_keypair()
set_public_key(public_key)
set_relin_keys(relin_keys)
display_config()

set_private_key(private_key)

display_config()


# The server
def process(x):
    return x**3 - 3*x + 1


# The client
sensitive_data = [-30, -5, 17, 28]
for entry in sensitive_data:
    encrypted = encrypt(entry) # Encrypt the data...
    result = process(encrypted) # Process the encrypted data on the server...
    print(entry, decrypt(result)) # Decrypt the result on the client.
Beispiel #7
0
 def test_pow(self):
     for i in range(ITERATIONS):
         a = self.rand() / 500
         b = random.randint(0, 4)
         self.assertAlmostEqual(decrypt(encrypt(a)**b), a**b, places=3)
Beispiel #8
0
 def test_div(self):
     for i in range(ITERATIONS):
         a = self.rand()
         b = (2 * random.randint(0, 1) - 1) * random.uniform(1, 100)
         self.assertAlmostEqual(decrypt(encrypt(a) / b), a / b, places=3)
Beispiel #9
0
 def test_pow(self):
     for i in range(ITERATIONS):
         a = random.randint(-7, 7)
         b = random.randint(0, 6)
         self.assertEqual(decrypt(encrypt(a)**b), a**b)
Beispiel #10
0
 def test_pow_error(self):
     a = lambda: encrypt(3)**-1
     self.assertRaises(TypeError, a)
Beispiel #11
0
 def binop_test(self, binop):
     for i in range(ITERATIONS):
         a = self.randint()
         b = self.randint()
         self.assertEqual(decrypt(binop(encrypt(a), encrypt(b))),
                          binop(a, b))
Beispiel #12
0
from pathlib import Path
from simplefhe import encrypt, load_public_key, load_relin_keys, display_config

load_public_key('keys/public.key')
load_relin_keys('keys/relin.key')
display_config()

# Encrypt our data (client-side)
sensitive_data = [-30, -5, 17, 28]
Path('inputs').mkdir(exist_ok=True)

for i, entry in enumerate(sensitive_data):
    encrypted = encrypt(entry)
    encrypted.save(f'inputs/{i}.dat')
    print(f'[CLIENT] Input {entry} encrypted to inputs/{i}.dat')

# We may then safely send these files to the server
# over a (possibly insecure) network connection
Beispiel #13
0
from simplefhe import (encrypt, decrypt, generate_keypair, set_public_key,
                       set_private_key, set_relin_keys, initialize,
                       display_config)

initialize('int')

public_key, private_key, relin_key = generate_keypair()
set_private_key(private_key)
set_public_key(public_key)
set_relin_keys(relin_key)

display_config()


# The server
def process(x):
    return x**21


# The client
sensitive_data = [-3, 1, 3, 10]
for entry in sensitive_data:
    insecure_result = process(entry)
    secure_result = decrypt(process(encrypt(entry)))
    print(entry, insecure_result, secure_result)
Beispiel #14
0
from simplefhe import initialize, encrypt, load_public_key, load_relin_keys


# Initialization and keys
initialize('float')
load_public_key('keys/public.key')
load_relin_keys('keys/relin.key')
Path('inputs').mkdir(exist_ok=True)


# We generate example datapoints according to a linear model:
# y = 3.2 x1 - 1.7 x2 + 0.8 x3 + noise
COEFFICIENTS = np.array([3.2, -1.7, 0.8])
def generate_point():
    xs = np.random.normal(size=3, scale=10)
    noise = np.random.normal(scale=0.2)
    y = np.inner(xs, COEFFICIENTS) + noise
    return (xs, y)


# Generate and save encrypted datapoints
N_DATAPOINTS = 50
for i in range(N_DATAPOINTS):
    print(f'Generating datapoint {i+1} of {N_DATAPOINTS}')
    xs, y = generate_point()

    encrypt(y).save(f'inputs/y-{i}.dat')
    for j, x in enumerate(xs):
        encrypt(x).save(f'inputs/x{j}-{i}.dat')
Beispiel #15
0
 def test_repr(self):
     a = encrypt(3)
     self.assertEqual(repr(a), '<encrypted int>')