Пример #1
0
    def test_reduction_balancer(self):
        """ Check that reductions are balanced under balance_reductions=true """

        prog = EvaProgram('ReductionTree', vec_size=16384)
        with prog:
            x1 = Input('x1')
            x2 = Input('x2')
            x3 = Input('x3')
            x4 = Input('x4')
            Output('y', (x1 * (x2 * (x3 * x4))) + (x1 + (x2 + (x3 + x4))))

        prog.set_output_ranges(20)
        prog.set_input_scales(60)

        progc, params, signature = self.assert_compiles_and_matches_reference(
            prog,
            config={
                'rescaler': 'always',
                'balance_reductions': 'false',
                'warn_vec_size': 'false'
            })
        self.assertEqual(params.prime_bits, [60, 20, 60, 60, 60, 60])

        progc, params, signature = self.assert_compiles_and_matches_reference(
            prog,
            config={
                'rescaler': 'always',
                'balance_reductions': 'true',
                'warn_vec_size': 'false'
            })
        self.assertEqual(params.prime_bits, [60, 20, 60, 60, 60])
Пример #2
0
    def test_unary_ops(self):
        """ Test all unary ops """

        for unOp in [lambda x: x, lambda x: -x, lambda x: x**3, lambda x: 42]:
            for enc in [False, True]:
                prog = EvaProgram('UnOp', vec_size=64)
                with prog:
                    x = Input('x', enc)
                    Output('y', unOp(x))

                prog.set_output_ranges(20)
                prog.set_input_scales(30)

                self.assert_compiles_and_matches_reference(
                    prog, config={'warn_vec_size': 'false'})
Пример #3
0
    def test_rotations(self):
        """ Test all rotations """

        for rotOp in [lambda x, r: x << r, lambda x, r: x >> r]:
            for enc in [False, True]:
                for rot in range(-2, 2):
                    prog = EvaProgram('RotOp', vec_size=8)
                    with prog:
                        x = Input('x')
                        Output('y', rotOp(x, rot))

                    prog.set_output_ranges(20)
                    prog.set_input_scales(30)

                    self.assert_compiles_and_matches_reference(
                        prog, config={'warn_vec_size': 'false'})
Пример #4
0
    def test_unencrypted_computation(self):
        """ Test computation on unencrypted values """

        for enc1 in [False, True]:
            for enc2 in [False, True]:
                prog = EvaProgram('UnencryptedInputs', vec_size=128)
                with prog:
                    x1 = Input('x1', enc1)
                    x2 = Input('x2', enc2)
                    Output('y', pow(x2, 3) + x1 * x2)

                prog.set_output_ranges(20)
                prog.set_input_scales(30)

                self.assert_compiles_and_matches_reference(
                    prog, config={'warn_vec_size': 'false'})
Пример #5
0
    def test_unsupported_security_level(self):
        """ Check that unsupported security levels error out """

        prog = EvaProgram('SecurityLevel', vec_size=512)
        with prog:
            x = Input('x')
            Output('y', 5 * x * x + 3 * x + x << 12 + 10)

        prog.set_output_ranges(20)
        prog.set_input_scales(30)

        self.assert_compiles_and_matches_reference(prog,
                                                   config={
                                                       'security_level':
                                                       '1024',
                                                       'warn_vec_size': 'false'
                                                   })
Пример #6
0
    def test_sobel_configs(self):
        """ Check accuracy of Sobel filter on random image with various compiler configurations """
        def convolutionXY(image, width, filter):
            for i in range(len(filter)):
                for j in range(len(filter[0])):
                    rotated = image << (i * width + j)
                    horizontal = rotated * filter[i][j]
                    vertical = rotated * filter[j][i]
                    if i == 0 and j == 0:
                        Ix = horizontal
                        Iy = vertical
                    else:
                        Ix += horizontal
                        Iy += vertical
            return Ix, Iy

        h = 90
        w = 90

        sobel = EvaProgram('sobel',
                           vec_size=2**(math.ceil(math.log(h * w, 2))))
        with sobel:
            image = Input('image')

            sobel_filter = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]

            a1 = 2.2137874823876622
            a2 = -1.0984324107372518
            a3 = 0.17254603006834726

            conv_hor, conv_ver = convolutionXY(image, w, sobel_filter)
            x = conv_hor**2 + conv_ver**2
            Output('image', x * a1 + x**2 * a2 + x**3 * a3)

        sobel.set_input_scales(45)
        sobel.set_output_ranges(20)

        for rescaler in ['lazy_waterline', 'eager_waterline', 'always']:
            for balance_reductions in ['true', 'false']:
                self.assert_compiles_and_matches_reference(
                    sobel,
                    config={
                        'rescaler': rescaler,
                        'balance_reductions': balance_reductions
                    })
Пример #7
0
    def test_seal_no_throw_on_transparent(self):
        """ Check that SEAL is compiled with -DSEAL_THROW_ON_TRANSPARENT_CIPHERTEXT=OFF
        
            An HE compiler cannot in general work with transparent ciphertext detection
            turned on because it is not possible to statically detect all situations that
            result in them. For example, x1-x2 is transparent only if the user gives the
            same ciphertext as both inputs."""

        prog = EvaProgram('Transparent', vec_size=4096)
        with prog:
            x = Input('x')
            Output('y', x - x + x * 0)

        prog.set_output_ranges(20)
        prog.set_input_scales(30)

        self.assert_compiles_and_matches_reference(
            prog, config={'warn_vec_size': 'false'})
Пример #8
0
    def test_high_inner_term_scale(self):
        """ Test lazy waterline rescaler with a program causing a high inner term scale

            This test was added for a bug that was an interaction between
            rescaling not being inserted (causing high scales to be accumulated)
            and parameter selection not handling high scales in inner terms."""

        prog = EvaProgram('HighInnerTermScale', vec_size=4)
        with prog:
            x1 = Input('x1')
            x2 = Input('x2')
            Output('y', x1 * x1 * x2)

        prog.set_output_ranges(20)
        prog.set_input_scales(60)

        self.assert_compiles_and_matches_reference(
            prog, config={'rescaler': 'lazy_waterline'})
Пример #9
0
    def test_bin_ops(self):
        """ Test all binary ops """

        for binOp in [
                lambda a, b: a + b, lambda a, b: a - b, lambda a, b: a * b
        ]:
            for enc1 in [False, True]:
                for enc2 in [False, True]:
                    prog = EvaProgram('BinOp', vec_size=64)
                    with prog:
                        a = Input('a', enc1)
                        b = Input('b', enc2)
                        Output('y', binOp(a, b))

                    prog.set_output_ranges(20)
                    prog.set_input_scales(30)

                    self.assert_compiles_and_matches_reference(
                        prog, config={'warn_vec_size': 'false'})
Пример #10
0
    def test_large_and_small(self):
        """ Check that a ciphertext with very large and small values decodes accurately
            
            This test was added to track a common bug in CKKS implementations,
            where double precision floating points used in decoding fail to
            provide good accuracy for small values in ciphertexts when other
            very large values are present."""

        prog = EvaProgram('LargeAndSmall', vec_size=4)
        with prog:
            x = Input('x')
            Output('y', pow(x, 8))

        prog.set_output_ranges(60)
        prog.set_input_scales(60)

        inputs = {'x': [0, 1, 10, 100]}

        self.assert_compiles_and_matches_reference(
            prog, inputs, config={'warn_vec_size': 'false'})
Пример #11
0
    def test_output_rescaled(self):
        """ Check that the lazy waterline policy rescales outputs
        
            This test was added for a bug where outputs could be returned with
            more primes in their modulus than necessary, which causes them to
            take more space when serialized."""

        prog = EvaProgram('OutputRescaled', vec_size=4)
        with prog:
            x = Input('x')
            Output('y', x * x)

        prog.set_output_ranges(20)
        prog.set_input_scales(60)

        compiler = CKKSCompiler(config={
            'rescaler': 'lazy_waterline',
            'warn_vec_size': 'false'
        })
        prog, params, signature = compiler.compile(prog)
        self.assertEqual(params.prime_bits, [60, 20, 60, 60])
Пример #12
0
def compile():
    print('Compile time')

    chi_squared = EvaProgram('Chi Squared', vec_size=1)
    with chi_squared:
        n0 = Input('n0')
        n1 = Input('n1')
        n2 = Input('n2')

        Output('alpha', (4 * n0 * n2 - n1**2)**2)
        Output('beta1', 2 * ((2 * n0 + n1)**2))
        Output('beta2', (2 * n0 + n1) * (2 * n2 + n1))
        Output('beta3', 2 * (2 * n2 + n1)**2)

        chi_squared.set_output_ranges(60)
        chi_squared.set_input_scales(60)

        compiler = CKKSCompiler()
        chi_squared, params, signature = compiler.compile(chi_squared)

        save(chi_squared, 'chi_squared.eva')
        save(params, 'chi_squared.evaparams')
        save(signature, 'chi_squared.evasignature')
Пример #13
0
    def test_security_levels(self):
        """ Check that all supported security levels work """

        security_levels = ['128', '192', '256']
        quantum_safety = ['false', 'true']

        for s in security_levels:
            for q in quantum_safety:
                prog = EvaProgram('SecurityLevel', vec_size=512)
                with prog:
                    x = Input('x')
                    Output('y', 5 * x * x + 3 * x + x << 12 + 10)

                prog.set_output_ranges(20)
                prog.set_input_scales(30)

                self.assert_compiles_and_matches_reference(
                    prog,
                    config={
                        'security_level': s,
                        'quantum_safe': q,
                        'warn_vec_size': 'false'
                    })
Пример #14
0
    def test_regression(self):
        """ Test batched compilation and execution of multiple linear regression programs """

        linreg = EvaProgram('linear_regression', vec_size=2048)
        with linreg:
            p = 63

            x = [Input(f'x{i}') for i in range(p)]
            e = Input('e')
            b0 = 6.56
            b = [i * 0.732 for i in range(p)]

            y = e + b0
            for i in range(p):
                t = x[i] * b[i]
                y += t

            Output('y', y)

        linreg.set_input_scales(40)
        linreg.set_output_ranges(30)

        linreg_inputs = {
            'e':
            [(linreg.vec_size - i) * 0.001 for i in range(linreg.vec_size)]
        }
        for i in range(p):
            linreg_inputs[f'x{i}'] = [
                i * j * 0.01 for j in range(linreg.vec_size)
            ]

        polyreg = EvaProgram('polynomial_regression', vec_size=4096)
        with polyreg:
            p = 4

            x = Input('x')
            e = Input('e')
            b0 = 6.56
            b = [i * 0.732 for i in range(p)]

            y = e + b0
            for i in range(p):
                x_i = x
                for j in range(i):
                    x_i = x_i * x
                t = x_i * b[i]
                y += t

            Output('y', y)

        polyreg.set_input_scales(40)
        polyreg.set_output_ranges(30)

        polyreg_inputs = {
            'x': [i * 0.01 for i in range(polyreg.vec_size)],
            'e':
            [(polyreg.vec_size - i) * 0.001 for i in range(polyreg.vec_size)],
        }

        multireg = EvaProgram('multivariate_regression', vec_size=2048)
        with multireg:
            p = 63
            k = 4

            x = [Input(f'x{i}') for i in range(p)]
            e = [Input(f'e{j}') for j in range(k)]
            b0 = [j * 0.56 for j in range(k)]
            b = [[k * i * 0.732 for i in range(p)] for j in range(k)]

            y = [0 for j in range(k)]
            for j in range(k):
                y[j] = e[j] + b0[j]
                for i in range(p):
                    t = x[i] * b[j][i]
                    y[j] += t

            for j in range(k):
                Output(f'y{j}', y[j])

        multireg.set_input_scales(40)
        multireg.set_output_ranges(30)

        multireg_inputs = {}
        for i in range(p):
            multireg_inputs[f'x{i}'] = [
                i * j * 0.01 for j in range(multireg.vec_size)
            ]
        for j in range(k):
            multireg_inputs[f'e{j}'] = [(multireg.vec_size - i) * j * 0.001
                                        for i in range(multireg.vec_size)]

        compiler = CKKSCompiler(config={'warn_vec_size': 'false'})

        for prog, inputs in [(linreg, linreg_inputs),
                             (polyreg, polyreg_inputs),
                             (multireg, multireg_inputs)]:
            compiled_prog, params, signature = compiler.compile(prog)
            public_ctx, secret_ctx = generate_keys(params)
            enc_inputs = public_ctx.encrypt(inputs, signature)
            enc_outputs = public_ctx.execute(compiled_prog, enc_inputs)
            outputs = secret_ctx.decrypt(enc_outputs, signature)
            reference = evaluate(compiled_prog, inputs)
            self.assertTrue(valuation_mse(outputs, reference) < 0.01)
Пример #15
0
    def test_horizontal_sum(self):
        """ Test eva.std.numeric.horizontal_sum """

        for enc in [True, False]:
            prog = EvaProgram('HorizontalSum', vec_size=2048)
            with prog:
                x = Input('x', is_encrypted=enc)
                y = horizontal_sum(x)
                Output('y', y)

            prog.set_output_ranges(25)
            prog.set_input_scales(33)

            self.assert_compiles_and_matches_reference(
                prog, config={'warn_vec_size': 'false'})

        prog = EvaProgram('HorizontalSumConstant', vec_size=2048)
        with prog:
            y = horizontal_sum([1 for _ in range(prog.vec_size)])
            Output('y', y)

        prog.set_output_ranges(25)
        prog.set_input_scales(33)

        self.assert_compiles_and_matches_reference(
            prog, config={'warn_vec_size': 'false'})
Пример #16
0
            rotated = image << (i * width + j)
            horizontal = rotated * filter[i][j]
            vertical = rotated * filter[j][i]
            if i == 0 and j == 0:
                Ix = horizontal
                Iy = vertical
            else:
                Ix += horizontal
                Iy += vertical
    return Ix, Iy


h = 64
w = 64

sobel = EvaProgram('sobel', vec_size=h * w)
with sobel:
    image = Input('image')

    sobel_filter = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]

    a1 = 2.2137874823876622
    a2 = -1.0984324107372518
    a3 = 0.17254603006834726

    conv_hor, conv_ver = convolutionXY(image, w, sobel_filter)

    conv_hor2 = conv_hor**2
    conv_ver2 = conv_ver**2
    dsq = conv_hor2 + conv_ver2
    dsq2 = dsq * dsq
Пример #17
0
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.

from eva import EvaProgram, Input, Output, evaluate, save, load
from eva.ckks import CKKSCompiler
from eva.seal import generate_keys
from eva.metric import valuation_mse
import numpy as np

#################################################
print('Compile time')

poly = EvaProgram('Polynomial', vec_size=8)
with poly:
    x = Input('x')
    Output('y', 3 * x**2 + 5 * x - 2)

poly.set_output_ranges(20)
poly.set_input_scales(20)

compiler = CKKSCompiler()
poly, params, signature = compiler.compile(poly)

save(poly, 'poly.eva')
save(params, 'poly.evaparams')
save(signature, 'poly.evasignature')

#################################################
print('Key generation time')

params = load('poly.evaparams')
Пример #18
0
    def test_serialization(self):
        """ Test (de)serialization and check that results stay the same """

        poly = EvaProgram('Polynomial', vec_size=4096)
        with poly:
            x = Input('x')
            Output('y', 3 * x**2 + 5 * x - 2)

        poly.set_output_ranges(20)
        poly.set_input_scales(30)

        inputs = {'x': [i for i in range(poly.vec_size)]}
        reference = evaluate(poly, inputs)

        compiler = CKKSCompiler(config={'warn_vec_size': 'false'})
        poly, params, signature = compiler.compile(poly)

        with tempfile.TemporaryDirectory() as tmp_dir:
            tmp_path = lambda x: os.path.join(tmp_dir, x)

            save(poly, tmp_path('poly.eva'))
            save(params, tmp_path('poly.evaparams'))
            save(signature, tmp_path('poly.evasignature'))

            # Key generation time

            params = load(tmp_path('poly.evaparams'))

            public_ctx, secret_ctx = generate_keys(params)

            save(public_ctx, tmp_path('poly.sealpublic'))
            save(secret_ctx, tmp_path('poly.sealsecret'))

            # Runtime on client

            signature = load(tmp_path('poly.evasignature'))
            public_ctx = load(tmp_path('poly.sealpublic'))

            encInputs = public_ctx.encrypt(inputs, signature)

            save(encInputs, tmp_path('poly_inputs.sealvals'))

            # Runtime on server

            poly = load(tmp_path('poly.eva'))
            public_ctx = load(tmp_path('poly.sealpublic'))
            encInputs = load(tmp_path('poly_inputs.sealvals'))

            encOutputs = public_ctx.execute(poly, encInputs)

            save(encOutputs, tmp_path('poly_outputs.sealvals'))

            # Runtime back on client

            secret_ctx = load(tmp_path('poly.sealsecret'))
            encOutputs = load(tmp_path('poly_outputs.sealvals'))

        outputs = secret_ctx.decrypt(encOutputs, signature)

        reference_compiled = evaluate(poly, inputs)
        self.assertTrue(
            valuation_mse(reference, reference_compiled) < 0.0000000001)
        self.assertTrue(valuation_mse(outputs, reference) < 0.01)