├── .gitignore ├── .travis.yml ├── Aono.i ├── Aono.py ├── Aono_wrap.cxx ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── index.html ├── init.py ├── init_key_switching.py ├── init_operations_example.py ├── lib └── he │ ├── basic.h │ ├── keys.h │ ├── knuthYaoSampler.h │ ├── main.cpp │ ├── test.cpp │ └── utils.h ├── setup.py └── tests.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | build 3 | *.pyc 4 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.6" 4 | 5 | # install server dependencies 6 | before_install: 7 | - "sudo apt-get -y install musl-dev g++ swig make" 8 | - "wget https://pari.math.u-bordeaux.fr/pub/pari/unix/pari-2.9.3.tar.gz \ 9 | && tar -xzf pari-2.9.3.tar.gz \ 10 | && cd pari-2.9.3 \ 11 | && ./Configure \ 12 | && make all \ 13 | && make bench \ 14 | && sudo make install \ 15 | && ls \ 16 | && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ \ 17 | && echo $LD_LIBRARY_PATH \ 18 | && cd .." 19 | 20 | # install dependencies 21 | install: 22 | - "make compile" 23 | - "pip install pytest pytest--flake8" 24 | 25 | # run tests 26 | script: 27 | - make test 28 | -------------------------------------------------------------------------------- /Aono.i: -------------------------------------------------------------------------------- 1 | %module Aono 2 | %{ 3 | #include "lib/he/basic.h" 4 | %} 5 | extern void pari_init(size_t parisize, int maxprime); 6 | extern void pari_close(); 7 | typedef long *GEN; 8 | %include "lib/he/basic.h" 9 | %include "lib/he/keys.h" 10 | %include "lib/he/utils.h" 11 | 12 | %pythoncode%{ 13 | import atexit 14 | pari_init(2000000000, 2) 15 | atexit.register(pari_close) 16 | %} 17 | 18 | %include "carrays.i" 19 | %array_class(int, intArray); 20 | %extend pari_GEN{ 21 | pari_GEN(PyObject *int_list){ 22 | pari_GEN* result = new pari_GEN(); 23 | if(!PyList_Check(PyList_GetItem( int_list, 0))){ 24 | int *array = NULL; 25 | int nInts; 26 | if (PyList_Check( int_list )) 27 | { 28 | nInts = PyList_Size( int_list ); 29 | array = (int*) malloc( nInts * sizeof(int) ); 30 | for ( int ii = 0; ii < nInts; ii++ ){ 31 | PyObject *oo = PyList_GetItem( int_list, ii); 32 | if ( PyInt_Check( oo ) ) 33 | array[ ii ] = ( int ) PyInt_AsLong( oo ); 34 | } 35 | } 36 | GEN x; 37 | x = cgetg(nInts + 1, t_VEC); 38 | for(int i = 0; i < nInts; i++) 39 | gel(x, i + 1) = stoi(array[i]); 40 | result->initialize(x); 41 | return result; 42 | } 43 | else{ 44 | int *array = NULL; 45 | int **arrofarray = NULL; 46 | int nInts; 47 | int nOutInts; 48 | if (PyList_Check( int_list )) 49 | { 50 | nOutInts = PyList_Size( int_list ); 51 | arrofarray = (int**) malloc( nOutInts * sizeof(int*) ); 52 | for ( int jj = 0; jj < nOutInts; jj++ ){ 53 | nInts = PyList_Size(PyList_GetItem( int_list, jj) ); 54 | array = (int*) malloc( nInts * sizeof(int) ); 55 | for ( int ii = 0; ii < nInts; ii++ ){ 56 | PyObject *oo = PyList_GetItem(PyList_GetItem( int_list, jj), ii); 57 | if ( PyInt_Check( oo ) ){ 58 | array[ ii ] = ( int ) PyInt_AsLong( oo ); 59 | } 60 | 61 | } 62 | arrofarray[jj] = array; 63 | } 64 | } 65 | GEN x; 66 | x = zeromatcopy(nOutInts, nInts); 67 | for(int j = 0; j < nOutInts; j++){ 68 | for(int i = 0; i < nInts; i++) 69 | gel(gel(x, i + 1), j + 1) = stoi(arrofarray[j][i]); 70 | } 71 | result->initialize(x); 72 | return result; 73 | } 74 | 75 | } 76 | 77 | char* __str__(){ 78 | return GENtostr(self->value); 79 | } 80 | 81 | pari_GEN __getitem__(int key){ 82 | pari_GEN result; 83 | result.value = gel(self->value, key + 1); 84 | return result; 85 | } 86 | 87 | pari_GEN sub_mat_array(int key_1, int key_2){ 88 | pari_GEN result; 89 | result.value = cgetg(key_2 - key_1 + 1, t_VEC); 90 | int cnt = 0; 91 | for(int i = key_1; i < key_2; i++) 92 | gel(result.value, 1+cnt++) = gel(gel(self->value, i + 1), 1); 93 | return result; 94 | } 95 | 96 | pari_GEN sub_mat_array(int row_1, int row_2, int col_1, int col_2){ 97 | pari_GEN result; 98 | result.value = zeromatcopy(row_2 - row_1, col_2 - col_1); 99 | for(int j = col_1; j < col_2; j++){ 100 | for(int i = row_1; i < row_2; i++){ 101 | gel(gel(result.value, 1+(j-col_1)), 1+(i-row_1)) = gel(gel(self->value, j + 1), i + 1); 102 | } 103 | } 104 | return result; 105 | } 106 | 107 | pari_GEN sub_array(int key_1, int key_2){ 108 | pari_GEN result; 109 | result.value = cgetg(key_2 - key_1 + 1, t_VEC); 110 | for(int i = key_1; i < key_2; i++) 111 | gel(result.value, i + 1) = gel(self->value, i + 1); 112 | return result; 113 | } 114 | }; 115 | 116 | %extend ciphertext{ 117 | ciphertext(PyObject *int_list, public_key* pk){ 118 | ciphertext* result = new ciphertext(); 119 | int *array = NULL; 120 | int nInts; 121 | if (PyList_Check( int_list )) 122 | { 123 | nInts = PyList_Size( int_list ); 124 | array = (int*) malloc( nInts * sizeof(int) ); 125 | for ( int ii = 0; ii < nInts; ii++ ){ 126 | PyObject *oo = PyList_GetItem( int_list, ii); 127 | if ( PyInt_Check( oo ) ) 128 | array[ ii ] = ( int ) PyInt_AsLong( oo ); 129 | } 130 | } 131 | pari_GEN pt; 132 | pt.value = cgetg(nInts + 1, t_VEC); 133 | for(int i = 0; i < nInts; i++) 134 | gel(pt.value, i + 1) = stoi(array[i]); 135 | result->packing_method(pt, pk); 136 | return result; 137 | } 138 | 139 | 140 | ciphertext __mul__(const int pt){ 141 | ciphertext result; 142 | pari_GEN pt_GEN(pt); 143 | result.value = plaintext_multiplication(self->value, pt_GEN); 144 | result.params = self->params; 145 | result.pk = self->pk; 146 | return result; 147 | } 148 | 149 | ciphertext __rmul__(const int pt){ 150 | ciphertext result; 151 | pari_GEN pt_GEN(pt); 152 | result.value = plaintext_multiplication(self->value, pt_GEN); 153 | result.params = self->params; 154 | result.pk = self->pk; 155 | return result; 156 | } 157 | }; 158 | -------------------------------------------------------------------------------- /Aono.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 3.0.12 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info >= (2, 7, 0): 9 | def swig_import_helper(): 10 | import importlib 11 | pkg = __name__.rpartition('.')[0] 12 | mname = '.'.join((pkg, '_Aono')).lstrip('.') 13 | try: 14 | return importlib.import_module(mname) 15 | except ImportError: 16 | return importlib.import_module('_Aono') 17 | _Aono = swig_import_helper() 18 | del swig_import_helper 19 | elif _swig_python_version_info >= (2, 6, 0): 20 | def swig_import_helper(): 21 | from os.path import dirname 22 | import imp 23 | fp = None 24 | try: 25 | fp, pathname, description = imp.find_module('_Aono', [dirname(__file__)]) 26 | except ImportError: 27 | import _Aono 28 | return _Aono 29 | try: 30 | _mod = imp.load_module('_Aono', fp, pathname, description) 31 | finally: 32 | if fp is not None: 33 | fp.close() 34 | return _mod 35 | _Aono = swig_import_helper() 36 | del swig_import_helper 37 | else: 38 | import _Aono 39 | del _swig_python_version_info 40 | 41 | try: 42 | _swig_property = property 43 | except NameError: 44 | pass # Python < 2.2 doesn't have 'property'. 45 | 46 | try: 47 | import builtins as __builtin__ 48 | except ImportError: 49 | import __builtin__ 50 | 51 | def _swig_setattr_nondynamic(self, class_type, name, value, static=1): 52 | if (name == "thisown"): 53 | return self.this.own(value) 54 | if (name == "this"): 55 | if type(value).__name__ == 'SwigPyObject': 56 | self.__dict__[name] = value 57 | return 58 | method = class_type.__swig_setmethods__.get(name, None) 59 | if method: 60 | return method(self, value) 61 | if (not static): 62 | if _newclass: 63 | object.__setattr__(self, name, value) 64 | else: 65 | self.__dict__[name] = value 66 | else: 67 | raise AttributeError("You cannot add attributes to %s" % self) 68 | 69 | 70 | def _swig_setattr(self, class_type, name, value): 71 | return _swig_setattr_nondynamic(self, class_type, name, value, 0) 72 | 73 | 74 | def _swig_getattr(self, class_type, name): 75 | if (name == "thisown"): 76 | return self.this.own() 77 | method = class_type.__swig_getmethods__.get(name, None) 78 | if method: 79 | return method(self) 80 | raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name)) 81 | 82 | 83 | def _swig_repr(self): 84 | try: 85 | strthis = "proxy of " + self.this.__repr__() 86 | except __builtin__.Exception: 87 | strthis = "" 88 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 89 | 90 | try: 91 | _object = object 92 | _newclass = 1 93 | except __builtin__.Exception: 94 | class _object: 95 | pass 96 | _newclass = 0 97 | 98 | 99 | def pari_init(parisize, maxprime): 100 | return _Aono.pari_init(parisize, maxprime) 101 | pari_init = _Aono.pari_init 102 | 103 | def pari_close(): 104 | return _Aono.pari_close() 105 | pari_close = _Aono.pari_close 106 | class ciphertext(_object): 107 | __swig_setmethods__ = {} 108 | __setattr__ = lambda self, name, value: _swig_setattr(self, ciphertext, name, value) 109 | __swig_getmethods__ = {} 110 | __getattr__ = lambda self, name: _swig_getattr(self, ciphertext, name) 111 | __repr__ = _swig_repr 112 | __swig_setmethods__["value"] = _Aono.ciphertext_value_set 113 | __swig_getmethods__["value"] = _Aono.ciphertext_value_get 114 | if _newclass: 115 | value = _swig_property(_Aono.ciphertext_value_get, _Aono.ciphertext_value_set) 116 | __swig_setmethods__["degree"] = _Aono.ciphertext_degree_set 117 | __swig_getmethods__["degree"] = _Aono.ciphertext_degree_get 118 | if _newclass: 119 | degree = _swig_property(_Aono.ciphertext_degree_get, _Aono.ciphertext_degree_set) 120 | __swig_setmethods__["pk"] = _Aono.ciphertext_pk_set 121 | __swig_getmethods__["pk"] = _Aono.ciphertext_pk_get 122 | if _newclass: 123 | pk = _swig_property(_Aono.ciphertext_pk_get, _Aono.ciphertext_pk_set) 124 | __swig_setmethods__["params"] = _Aono.ciphertext_params_set 125 | __swig_getmethods__["params"] = _Aono.ciphertext_params_get 126 | if _newclass: 127 | params = _swig_property(_Aono.ciphertext_params_get, _Aono.ciphertext_params_set) 128 | __swig_destroy__ = _Aono.delete_ciphertext 129 | __del__ = lambda self: None 130 | 131 | def packing_method(self, m, pk): 132 | return _Aono.ciphertext_packing_method(self, m, pk) 133 | 134 | def initialize(self, *args): 135 | return _Aono.ciphertext_initialize(self, *args) 136 | 137 | def __add__(self, ct): 138 | return _Aono.ciphertext___add__(self, ct) 139 | 140 | def __sub__(self, ct): 141 | return _Aono.ciphertext___sub__(self, ct) 142 | 143 | def decrypt(self, sk): 144 | return _Aono.ciphertext_decrypt(self, sk) 145 | 146 | def __init__(self, *args): 147 | this = _Aono.new_ciphertext(*args) 148 | try: 149 | self.this.append(this) 150 | except __builtin__.Exception: 151 | self.this = this 152 | 153 | def __mul__(self, *args): 154 | return _Aono.ciphertext___mul__(self, *args) 155 | 156 | def __rmul__(self, pt): 157 | return _Aono.ciphertext___rmul__(self, pt) 158 | ciphertext_swigregister = _Aono.ciphertext_swigregister 159 | ciphertext_swigregister(ciphertext) 160 | 161 | class updation_key(_object): 162 | __swig_setmethods__ = {} 163 | __setattr__ = lambda self, name, value: _swig_setattr(self, updation_key, name, value) 164 | __swig_getmethods__ = {} 165 | __getattr__ = lambda self, name: _swig_getattr(self, updation_key, name) 166 | __repr__ = _swig_repr 167 | __swig_setmethods__["params"] = _Aono.updation_key_params_set 168 | __swig_getmethods__["params"] = _Aono.updation_key_params_get 169 | if _newclass: 170 | params = _swig_property(_Aono.updation_key_params_get, _Aono.updation_key_params_set) 171 | __swig_setmethods__["params_old"] = _Aono.updation_key_params_old_set 172 | __swig_getmethods__["params_old"] = _Aono.updation_key_params_old_get 173 | if _newclass: 174 | params_old = _swig_property(_Aono.updation_key_params_old_get, _Aono.updation_key_params_old_set) 175 | __swig_setmethods__["g"] = _Aono.updation_key_g_set 176 | __swig_getmethods__["g"] = _Aono.updation_key_g_get 177 | if _newclass: 178 | g = _swig_property(_Aono.updation_key_g_get, _Aono.updation_key_g_set) 179 | 180 | def __init__(self, *args): 181 | this = _Aono.new_updation_key(*args) 182 | try: 183 | self.this.append(this) 184 | except __builtin__.Exception: 185 | self.this = this 186 | 187 | def initialize(self, X, Y, params, params_old, g, pk): 188 | return _Aono.updation_key_initialize(self, X, Y, params, params_old, g, pk) 189 | 190 | def cipher_switch(self, ct): 191 | return _Aono.updation_key_cipher_switch(self, ct) 192 | 193 | def serialize(self): 194 | return _Aono.updation_key_serialize(self) 195 | __swig_destroy__ = _Aono.delete_updation_key 196 | __del__ = lambda self: None 197 | updation_key_swigregister = _Aono.updation_key_swigregister 198 | updation_key_swigregister(updation_key) 199 | 200 | class updation_key_gen(_object): 201 | __swig_setmethods__ = {} 202 | __setattr__ = lambda self, name, value: _swig_setattr(self, updation_key_gen, name, value) 203 | __swig_getmethods__ = {} 204 | __getattr__ = lambda self, name: _swig_getattr(self, updation_key_gen, name) 205 | __repr__ = _swig_repr 206 | 207 | def __init__(self): 208 | this = _Aono.new_updation_key_gen() 209 | try: 210 | self.this.append(this) 211 | except __builtin__.Exception: 212 | self.this = this 213 | 214 | def generate_key(self, key1, key2): 215 | return _Aono.updation_key_gen_generate_key(self, key1, key2) 216 | __swig_destroy__ = _Aono.delete_updation_key_gen 217 | __del__ = lambda self: None 218 | updation_key_gen_swigregister = _Aono.updation_key_gen_swigregister 219 | updation_key_gen_swigregister(updation_key_gen) 220 | 221 | class secret_key(_object): 222 | __swig_setmethods__ = {} 223 | __setattr__ = lambda self, name, value: _swig_setattr(self, secret_key, name, value) 224 | __swig_getmethods__ = {} 225 | __getattr__ = lambda self, name: _swig_getattr(self, secret_key, name) 226 | __repr__ = _swig_repr 227 | __swig_setmethods__["params"] = _Aono.secret_key_params_set 228 | __swig_getmethods__["params"] = _Aono.secret_key_params_get 229 | if _newclass: 230 | params = _swig_property(_Aono.secret_key_params_get, _Aono.secret_key_params_set) 231 | 232 | def __init__(self, *args): 233 | this = _Aono.new_secret_key(*args) 234 | try: 235 | self.this.append(this) 236 | except __builtin__.Exception: 237 | self.this = this 238 | 239 | def initialize(self, sk, params): 240 | return _Aono.secret_key_initialize(self, sk, params) 241 | 242 | def decrypt(self, ct): 243 | return _Aono.secret_key_decrypt(self, ct) 244 | 245 | def serialize(self): 246 | return _Aono.secret_key_serialize(self) 247 | __swig_destroy__ = _Aono.delete_secret_key 248 | __del__ = lambda self: None 249 | secret_key_swigregister = _Aono.secret_key_swigregister 250 | secret_key_swigregister(secret_key) 251 | 252 | class public_key(_object): 253 | __swig_setmethods__ = {} 254 | __setattr__ = lambda self, name, value: _swig_setattr(self, public_key, name, value) 255 | __swig_getmethods__ = {} 256 | __getattr__ = lambda self, name: _swig_getattr(self, public_key, name) 257 | __repr__ = _swig_repr 258 | __swig_setmethods__["params"] = _Aono.public_key_params_set 259 | __swig_getmethods__["params"] = _Aono.public_key_params_get 260 | if _newclass: 261 | params = _swig_property(_Aono.public_key_params_get, _Aono.public_key_params_set) 262 | __swig_setmethods__["g"] = _Aono.public_key_g_set 263 | __swig_getmethods__["g"] = _Aono.public_key_g_get 264 | if _newclass: 265 | g = _swig_property(_Aono.public_key_g_get, _Aono.public_key_g_set) 266 | 267 | def __init__(self, *args): 268 | this = _Aono.new_public_key(*args) 269 | try: 270 | self.this.append(this) 271 | except __builtin__.Exception: 272 | self.this = this 273 | 274 | def initialize(self, pk, params, g): 275 | return _Aono.public_key_initialize(self, pk, params, g) 276 | 277 | def encrypt(self, m): 278 | return _Aono.public_key_encrypt(self, m) 279 | 280 | def serialize(self): 281 | return _Aono.public_key_serialize(self) 282 | __swig_destroy__ = _Aono.delete_public_key 283 | __del__ = lambda self: None 284 | public_key_swigregister = _Aono.public_key_swigregister 285 | public_key_swigregister(public_key) 286 | 287 | class key_pair(_object): 288 | __swig_setmethods__ = {} 289 | __setattr__ = lambda self, name, value: _swig_setattr(self, key_pair, name, value) 290 | __swig_getmethods__ = {} 291 | __getattr__ = lambda self, name: _swig_getattr(self, key_pair, name) 292 | __repr__ = _swig_repr 293 | __swig_setmethods__["sk"] = _Aono.key_pair_sk_set 294 | __swig_getmethods__["sk"] = _Aono.key_pair_sk_get 295 | if _newclass: 296 | sk = _swig_property(_Aono.key_pair_sk_get, _Aono.key_pair_sk_set) 297 | __swig_setmethods__["pk"] = _Aono.key_pair_pk_set 298 | __swig_getmethods__["pk"] = _Aono.key_pair_pk_get 299 | if _newclass: 300 | pk = _swig_property(_Aono.key_pair_pk_get, _Aono.key_pair_pk_set) 301 | 302 | def __init__(self): 303 | this = _Aono.new_key_pair() 304 | try: 305 | self.this.append(this) 306 | except __builtin__.Exception: 307 | self.this = this 308 | __swig_destroy__ = _Aono.delete_key_pair 309 | __del__ = lambda self: None 310 | key_pair_swigregister = _Aono.key_pair_swigregister 311 | key_pair_swigregister(key_pair) 312 | 313 | class key_gen(_object): 314 | __swig_setmethods__ = {} 315 | __setattr__ = lambda self, name, value: _swig_setattr(self, key_gen, name, value) 316 | __swig_getmethods__ = {} 317 | __getattr__ = lambda self, name: _swig_getattr(self, key_gen, name) 318 | __repr__ = _swig_repr 319 | 320 | def __init__(self): 321 | this = _Aono.new_key_gen() 322 | try: 323 | self.this.append(this) 324 | except __builtin__.Exception: 325 | self.this = this 326 | 327 | def generate_key(self, arg2, l, n, s, sigma, degree_p): 328 | return _Aono.key_gen_generate_key(self, arg2, l, n, s, sigma, degree_p) 329 | __swig_destroy__ = _Aono.delete_key_gen 330 | __del__ = lambda self: None 331 | key_gen_swigregister = _Aono.key_gen_swigregister 332 | key_gen_swigregister(key_gen) 333 | 334 | M_PI = _Aono.M_PI 335 | precision = _Aono.precision 336 | class pari_GEN(_object): 337 | __swig_setmethods__ = {} 338 | __setattr__ = lambda self, name, value: _swig_setattr(self, pari_GEN, name, value) 339 | __swig_getmethods__ = {} 340 | __getattr__ = lambda self, name: _swig_getattr(self, pari_GEN, name) 341 | __repr__ = _swig_repr 342 | __swig_setmethods__["value"] = _Aono.pari_GEN_value_set 343 | __swig_getmethods__["value"] = _Aono.pari_GEN_value_get 344 | if _newclass: 345 | value = _swig_property(_Aono.pari_GEN_value_get, _Aono.pari_GEN_value_set) 346 | 347 | def initialize(self, x): 348 | return _Aono.pari_GEN_initialize(self, x) 349 | 350 | def __add__(self, GEN_2): 351 | return _Aono.pari_GEN___add__(self, GEN_2) 352 | 353 | def __mul__(self, GEN_2): 354 | return _Aono.pari_GEN___mul__(self, GEN_2) 355 | 356 | def __truediv__(self, *args): 357 | return _Aono.pari_GEN___truediv__(self, *args) 358 | __div__ = __truediv__ 359 | 360 | 361 | 362 | def __sub__(self, GEN_2): 363 | return _Aono.pari_GEN___sub__(self, GEN_2) 364 | 365 | def __mod__(self, GEN_2): 366 | return _Aono.pari_GEN___mod__(self, GEN_2) 367 | 368 | def __eq__(self, GEN_2): 369 | return _Aono.pari_GEN___eq__(self, GEN_2) 370 | 371 | def __init__(self, *args): 372 | this = _Aono.new_pari_GEN(*args) 373 | try: 374 | self.this.append(this) 375 | except __builtin__.Exception: 376 | self.this = this 377 | 378 | def __str__(self): 379 | return _Aono.pari_GEN___str__(self) 380 | 381 | def __getitem__(self, key): 382 | return _Aono.pari_GEN___getitem__(self, key) 383 | 384 | def sub_mat_array(self, *args): 385 | return _Aono.pari_GEN_sub_mat_array(self, *args) 386 | 387 | def sub_array(self, key_1, key_2): 388 | return _Aono.pari_GEN_sub_array(self, key_1, key_2) 389 | __swig_destroy__ = _Aono.delete_pari_GEN 390 | __del__ = lambda self: None 391 | pari_GEN_swigregister = _Aono.pari_GEN_swigregister 392 | pari_GEN_swigregister(pari_GEN) 393 | cvar = _Aono.cvar 394 | 395 | class parameters(_object): 396 | __swig_setmethods__ = {} 397 | __setattr__ = lambda self, name, value: _swig_setattr(self, parameters, name, value) 398 | __swig_getmethods__ = {} 399 | __getattr__ = lambda self, name: _swig_getattr(self, parameters, name) 400 | __repr__ = _swig_repr 401 | __swig_setmethods__["q"] = _Aono.parameters_q_set 402 | __swig_getmethods__["q"] = _Aono.parameters_q_get 403 | if _newclass: 404 | q = _swig_property(_Aono.parameters_q_get, _Aono.parameters_q_set) 405 | __swig_setmethods__["p"] = _Aono.parameters_p_set 406 | __swig_getmethods__["p"] = _Aono.parameters_p_get 407 | if _newclass: 408 | p = _swig_property(_Aono.parameters_p_get, _Aono.parameters_p_set) 409 | __swig_setmethods__["_lambda"] = _Aono.parameters__lambda_set 410 | __swig_getmethods__["_lambda"] = _Aono.parameters__lambda_get 411 | if _newclass: 412 | _lambda = _swig_property(_Aono.parameters__lambda_get, _Aono.parameters__lambda_set) 413 | __swig_setmethods__["l"] = _Aono.parameters_l_set 414 | __swig_getmethods__["l"] = _Aono.parameters_l_get 415 | if _newclass: 416 | l = _swig_property(_Aono.parameters_l_get, _Aono.parameters_l_set) 417 | __swig_setmethods__["s"] = _Aono.parameters_s_set 418 | __swig_getmethods__["s"] = _Aono.parameters_s_get 419 | if _newclass: 420 | s = _swig_property(_Aono.parameters_s_get, _Aono.parameters_s_set) 421 | __swig_setmethods__["n"] = _Aono.parameters_n_set 422 | __swig_getmethods__["n"] = _Aono.parameters_n_get 423 | if _newclass: 424 | n = _swig_property(_Aono.parameters_n_get, _Aono.parameters_n_set) 425 | __swig_setmethods__["sigma"] = _Aono.parameters_sigma_set 426 | __swig_getmethods__["sigma"] = _Aono.parameters_sigma_get 427 | if _newclass: 428 | sigma = _swig_property(_Aono.parameters_sigma_get, _Aono.parameters_sigma_set) 429 | 430 | def __init__(self): 431 | this = _Aono.new_parameters() 432 | try: 433 | self.this.append(this) 434 | except __builtin__.Exception: 435 | self.this = this 436 | __swig_destroy__ = _Aono.delete_parameters 437 | __del__ = lambda self: None 438 | parameters_swigregister = _Aono.parameters_swigregister 439 | parameters_swigregister(parameters) 440 | 441 | class ProbMatrixPack(_object): 442 | __swig_setmethods__ = {} 443 | __setattr__ = lambda self, name, value: _swig_setattr(self, ProbMatrixPack, name, value) 444 | __swig_getmethods__ = {} 445 | __getattr__ = lambda self, name: _swig_getattr(self, ProbMatrixPack, name) 446 | __repr__ = _swig_repr 447 | __swig_setmethods__["P"] = _Aono.ProbMatrixPack_P_set 448 | __swig_getmethods__["P"] = _Aono.ProbMatrixPack_P_get 449 | if _newclass: 450 | P = _swig_property(_Aono.ProbMatrixPack_P_get, _Aono.ProbMatrixPack_P_set) 451 | __swig_setmethods__["startPos"] = _Aono.ProbMatrixPack_startPos_set 452 | __swig_getmethods__["startPos"] = _Aono.ProbMatrixPack_startPos_get 453 | if _newclass: 454 | startPos = _swig_property(_Aono.ProbMatrixPack_startPos_get, _Aono.ProbMatrixPack_startPos_set) 455 | __swig_setmethods__["isInitialized"] = _Aono.ProbMatrixPack_isInitialized_set 456 | __swig_getmethods__["isInitialized"] = _Aono.ProbMatrixPack_isInitialized_get 457 | if _newclass: 458 | isInitialized = _swig_property(_Aono.ProbMatrixPack_isInitialized_get, _Aono.ProbMatrixPack_isInitialized_set) 459 | 460 | def __init__(self): 461 | this = _Aono.new_ProbMatrixPack() 462 | try: 463 | self.this.append(this) 464 | except __builtin__.Exception: 465 | self.this = this 466 | __swig_destroy__ = _Aono.delete_ProbMatrixPack 467 | __del__ = lambda self: None 468 | ProbMatrixPack_swigregister = _Aono.ProbMatrixPack_swigregister 469 | ProbMatrixPack_swigregister(ProbMatrixPack) 470 | 471 | class public_key_pack(_object): 472 | __swig_setmethods__ = {} 473 | __setattr__ = lambda self, name, value: _swig_setattr(self, public_key_pack, name, value) 474 | __swig_getmethods__ = {} 475 | __getattr__ = lambda self, name: _swig_getattr(self, public_key_pack, name) 476 | __repr__ = _swig_repr 477 | __swig_setmethods__["A"] = _Aono.public_key_pack_A_set 478 | __swig_getmethods__["A"] = _Aono.public_key_pack_A_get 479 | if _newclass: 480 | A = _swig_property(_Aono.public_key_pack_A_get, _Aono.public_key_pack_A_set) 481 | __swig_setmethods__["P"] = _Aono.public_key_pack_P_set 482 | __swig_getmethods__["P"] = _Aono.public_key_pack_P_get 483 | if _newclass: 484 | P = _swig_property(_Aono.public_key_pack_P_get, _Aono.public_key_pack_P_set) 485 | __swig_setmethods__["n"] = _Aono.public_key_pack_n_set 486 | __swig_getmethods__["n"] = _Aono.public_key_pack_n_get 487 | if _newclass: 488 | n = _swig_property(_Aono.public_key_pack_n_get, _Aono.public_key_pack_n_set) 489 | __swig_setmethods__["s"] = _Aono.public_key_pack_s_set 490 | __swig_getmethods__["s"] = _Aono.public_key_pack_s_get 491 | if _newclass: 492 | s = _swig_property(_Aono.public_key_pack_s_get, _Aono.public_key_pack_s_set) 493 | 494 | def __init__(self): 495 | this = _Aono.new_public_key_pack() 496 | try: 497 | self.this.append(this) 498 | except __builtin__.Exception: 499 | self.this = this 500 | __swig_destroy__ = _Aono.delete_public_key_pack 501 | __del__ = lambda self: None 502 | public_key_pack_swigregister = _Aono.public_key_pack_swigregister 503 | public_key_pack_swigregister(public_key_pack) 504 | 505 | class globalvars(_object): 506 | __swig_setmethods__ = {} 507 | __setattr__ = lambda self, name, value: _swig_setattr(self, globalvars, name, value) 508 | __swig_getmethods__ = {} 509 | __getattr__ = lambda self, name: _swig_getattr(self, globalvars, name) 510 | __repr__ = _swig_repr 511 | __swig_setmethods__["pPack"] = _Aono.globalvars_pPack_set 512 | __swig_getmethods__["pPack"] = _Aono.globalvars_pPack_get 513 | if _newclass: 514 | pPack = _swig_property(_Aono.globalvars_pPack_get, _Aono.globalvars_pPack_set) 515 | __swig_setmethods__["errorsModulo"] = _Aono.globalvars_errorsModulo_set 516 | __swig_getmethods__["errorsModulo"] = _Aono.globalvars_errorsModulo_get 517 | if _newclass: 518 | errorsModulo = _swig_property(_Aono.globalvars_errorsModulo_get, _Aono.globalvars_errorsModulo_set) 519 | 520 | def __init__(self): 521 | this = _Aono.new_globalvars() 522 | try: 523 | self.this.append(this) 524 | except __builtin__.Exception: 525 | self.this = this 526 | __swig_destroy__ = _Aono.delete_globalvars 527 | __del__ = lambda self: None 528 | globalvars_swigregister = _Aono.globalvars_swigregister 529 | globalvars_swigregister(globalvars) 530 | 531 | class cipher_text(_object): 532 | __swig_setmethods__ = {} 533 | __setattr__ = lambda self, name, value: _swig_setattr(self, cipher_text, name, value) 534 | __swig_getmethods__ = {} 535 | __getattr__ = lambda self, name: _swig_getattr(self, cipher_text, name) 536 | __repr__ = _swig_repr 537 | __swig_setmethods__["flag"] = _Aono.cipher_text_flag_set 538 | __swig_getmethods__["flag"] = _Aono.cipher_text_flag_get 539 | if _newclass: 540 | flag = _swig_property(_Aono.cipher_text_flag_get, _Aono.cipher_text_flag_set) 541 | __swig_setmethods__["comp1"] = _Aono.cipher_text_comp1_set 542 | __swig_getmethods__["comp1"] = _Aono.cipher_text_comp1_get 543 | if _newclass: 544 | comp1 = _swig_property(_Aono.cipher_text_comp1_get, _Aono.cipher_text_comp1_set) 545 | __swig_setmethods__["comp2"] = _Aono.cipher_text_comp2_set 546 | __swig_getmethods__["comp2"] = _Aono.cipher_text_comp2_get 547 | if _newclass: 548 | comp2 = _swig_property(_Aono.cipher_text_comp2_get, _Aono.cipher_text_comp2_set) 549 | 550 | def __init__(self): 551 | this = _Aono.new_cipher_text() 552 | try: 553 | self.this.append(this) 554 | except __builtin__.Exception: 555 | self.this = this 556 | __swig_destroy__ = _Aono.delete_cipher_text 557 | __del__ = lambda self: None 558 | cipher_text_swigregister = _Aono.cipher_text_swigregister 559 | cipher_text_swigregister(cipher_text) 560 | 561 | class cipher_text_mult(_object): 562 | __swig_setmethods__ = {} 563 | __setattr__ = lambda self, name, value: _swig_setattr(self, cipher_text_mult, name, value) 564 | __swig_getmethods__ = {} 565 | __getattr__ = lambda self, name: _swig_getattr(self, cipher_text_mult, name) 566 | __repr__ = _swig_repr 567 | __swig_setmethods__["flag"] = _Aono.cipher_text_mult_flag_set 568 | __swig_getmethods__["flag"] = _Aono.cipher_text_mult_flag_get 569 | if _newclass: 570 | flag = _swig_property(_Aono.cipher_text_mult_flag_get, _Aono.cipher_text_mult_flag_set) 571 | __swig_setmethods__["c"] = _Aono.cipher_text_mult_c_set 572 | __swig_getmethods__["c"] = _Aono.cipher_text_mult_c_get 573 | if _newclass: 574 | c = _swig_property(_Aono.cipher_text_mult_c_get, _Aono.cipher_text_mult_c_set) 575 | 576 | def __init__(self): 577 | this = _Aono.new_cipher_text_mult() 578 | try: 579 | self.this.append(this) 580 | except __builtin__.Exception: 581 | self.this = this 582 | __swig_destroy__ = _Aono.delete_cipher_text_mult 583 | __del__ = lambda self: None 584 | cipher_text_mult_swigregister = _Aono.cipher_text_mult_swigregister 585 | cipher_text_mult_swigregister(cipher_text_mult) 586 | 587 | 588 | def get_element(*args): 589 | return _Aono.get_element(*args) 590 | get_element = _Aono.get_element 591 | 592 | def print_GEN(*args): 593 | return _Aono.print_GEN(*args) 594 | print_GEN = _Aono.print_GEN 595 | 596 | def create_GEN(*args): 597 | return _Aono.create_GEN(*args) 598 | create_GEN = _Aono.create_GEN 599 | 600 | def Uniform(): 601 | return _Aono.Uniform() 602 | Uniform = _Aono.Uniform 603 | 604 | def Normal(): 605 | return _Aono.Normal() 606 | Normal = _Aono.Normal 607 | 608 | def Gauss(mu, sigma): 609 | return _Aono.Gauss(mu, sigma) 610 | Gauss = _Aono.Gauss 611 | 612 | def Sample(n, sigma): 613 | return _Aono.Sample(n, sigma) 614 | Sample = _Aono.Sample 615 | 616 | def generate_random(bit_length): 617 | return _Aono.generate_random(bit_length) 618 | generate_random = _Aono.generate_random 619 | 620 | def getGuassProbability(point, center, params): 621 | return _Aono.getGuassProbability(point, center, params) 622 | getGuassProbability = _Aono.getGuassProbability 623 | 624 | def genProbabilityMatrix(*args): 625 | return _Aono.genProbabilityMatrix(*args) 626 | genProbabilityMatrix = _Aono.genProbabilityMatrix 627 | 628 | def SampleKnuthYao(c, params, g): 629 | return _Aono.SampleKnuthYao(c, params, g) 630 | SampleKnuthYao = _Aono.SampleKnuthYao 631 | 632 | def initialize_sampler(*args): 633 | return _Aono.initialize_sampler(*args) 634 | initialize_sampler = _Aono.initialize_sampler 635 | 636 | def getGENsize(x): 637 | return _Aono.getGENsize(x) 638 | getGENsize = _Aono.getGENsize 639 | 640 | def getGEN_MATRIXsize(x): 641 | return _Aono.getGEN_MATRIXsize(x) 642 | getGEN_MATRIXsize = _Aono.getGEN_MATRIXsize 643 | 644 | def generate_secret_key(*args): 645 | return _Aono.generate_secret_key(*args) 646 | generate_secret_key = _Aono.generate_secret_key 647 | 648 | def generate_public_key(*args): 649 | return _Aono.generate_public_key(*args) 650 | generate_public_key = _Aono.generate_public_key 651 | 652 | def set_error_modulo(g, modulo): 653 | return _Aono.set_error_modulo(g, modulo) 654 | set_error_modulo = _Aono.set_error_modulo 655 | 656 | def access_value_pk(pk, flag): 657 | return _Aono.access_value_pk(pk, flag) 658 | access_value_pk = _Aono.access_value_pk 659 | 660 | def gen_params(arg1, l, n, s, sigma, degree_p): 661 | return _Aono.gen_params(arg1, l, n, s, sigma, degree_p) 662 | gen_params = _Aono.gen_params 663 | 664 | def create_message_matrix_repeated_input(arg1, arg2): 665 | return _Aono.create_message_matrix_repeated_input(arg1, arg2) 666 | create_message_matrix_repeated_input = _Aono.create_message_matrix_repeated_input 667 | 668 | def multiplication(arg1, arg2, arg3): 669 | return _Aono.multiplication(arg1, arg2, arg3) 670 | multiplication = _Aono.multiplication 671 | 672 | def encrypt_outside_class(m, pk, params, g): 673 | return _Aono.encrypt_outside_class(m, pk, params, g) 674 | encrypt_outside_class = _Aono.encrypt_outside_class 675 | 676 | def addition(ct_1, ct_2, params, pk, g): 677 | return _Aono.addition(ct_1, ct_2, params, pk, g) 678 | addition = _Aono.addition 679 | 680 | def subtraction(ct_1, ct_2, params, pk, g): 681 | return _Aono.subtraction(ct_1, ct_2, params, pk, g) 682 | subtraction = _Aono.subtraction 683 | 684 | def create_message_matrix(*args): 685 | return _Aono.create_message_matrix(*args) 686 | create_message_matrix = _Aono.create_message_matrix 687 | 688 | def see_ciphertext(c, index): 689 | return _Aono.see_ciphertext(c, index) 690 | see_ciphertext = _Aono.see_ciphertext 691 | 692 | def power2(x, n, kappa, l, q): 693 | return _Aono.power2(x, n, kappa, l, q) 694 | power2 = _Aono.power2 695 | 696 | def appendmat(m1, m2, col1, col2, row): 697 | return _Aono.appendmat(m1, m2, col1, col2, row) 698 | appendmat = _Aono.appendmat 699 | 700 | def bits(m, kappa, n): 701 | return _Aono.bits(m, kappa, n) 702 | bits = _Aono.bits 703 | 704 | def get_updation_parameters(params_old, n, s): 705 | return _Aono.get_updation_parameters(params_old, n, s) 706 | get_updation_parameters = _Aono.get_updation_parameters 707 | 708 | def plaintext_multiplication(ct, input): 709 | return _Aono.plaintext_multiplication(ct, input) 710 | plaintext_multiplication = _Aono.plaintext_multiplication 711 | 712 | import atexit 713 | pari_init(2000000000, 2) 714 | atexit.register(pari_close) 715 | 716 | class intArray(_object): 717 | __swig_setmethods__ = {} 718 | __setattr__ = lambda self, name, value: _swig_setattr(self, intArray, name, value) 719 | __swig_getmethods__ = {} 720 | __getattr__ = lambda self, name: _swig_getattr(self, intArray, name) 721 | __repr__ = _swig_repr 722 | 723 | def __init__(self, nelements): 724 | this = _Aono.new_intArray(nelements) 725 | try: 726 | self.this.append(this) 727 | except __builtin__.Exception: 728 | self.this = this 729 | __swig_destroy__ = _Aono.delete_intArray 730 | __del__ = lambda self: None 731 | 732 | def __getitem__(self, index): 733 | return _Aono.intArray___getitem__(self, index) 734 | 735 | def __setitem__(self, index, value): 736 | return _Aono.intArray___setitem__(self, index, value) 737 | 738 | def cast(self): 739 | return _Aono.intArray_cast(self) 740 | if _newclass: 741 | frompointer = staticmethod(_Aono.intArray_frompointer) 742 | else: 743 | frompointer = _Aono.intArray_frompointer 744 | intArray_swigregister = _Aono.intArray_swigregister 745 | intArray_swigregister(intArray) 746 | 747 | def intArray_frompointer(t): 748 | return _Aono.intArray_frompointer(t) 749 | intArray_frompointer = _Aono.intArray_frompointer 750 | 751 | # This file is compatible with both classic and new-style classes. 752 | 753 | 754 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile to build PyAono 2 | 3 | FROM alpine:edge 4 | 5 | RUN ["apk", "add", "--no-cache", "musl-dev", "g++", "make", "python3", "python3-dev", "swig"] 6 | # Even after specifying "gmp", we see this warning: 7 | # Your GMP library is incompatible with the compiler settings. 8 | # Building without GNU MP support 9 | 10 | # https://pari.math.u-bordeaux.fr/download.html 11 | RUN wget https://pari.math.u-bordeaux.fr/pub/pari/unix/pari-2.9.3.tar.gz \ 12 | && tar -xzf pari-2.9.3.tar.gz \ 13 | && cd pari-2.9.3 \ 14 | && ./Configure \ 15 | && make install 16 | 17 | RUN ["mkdir", "/PyAono"] 18 | COPY . /PyAono 19 | WORKDIR /PyAono 20 | 21 | RUN make compile 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License, Version 2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ 2 | 3 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 4 | 5 | 1. Definitions. 6 | 7 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 8 | 9 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 10 | 11 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 12 | 13 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 14 | 15 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 16 | 17 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 18 | 19 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 20 | 21 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 22 | 23 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 24 | 25 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 26 | 27 | 2. Grant of Copyright License. 28 | 29 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 30 | 31 | 3. Grant of Patent License. 32 | 33 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 34 | 35 | 4. Redistribution. 36 | 37 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 38 | 39 | You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 40 | 41 | 5. Submission of Contributions. 42 | 43 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 44 | 45 | 6. Trademarks. 46 | 47 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 48 | 49 | 7. Disclaimer of Warranty. 50 | 51 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 52 | 53 | 8. Limitation of Liability. 54 | 55 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 56 | 57 | 9. Accepting Warranty or Additional Liability. 58 | 59 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 60 | 61 | END OF TERMS AND CONDITIONS 62 | 63 | APPENDIX: How to apply the Apache License to your work 64 | 65 | To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. 66 | 67 | Copyright 2017 Open Mined contributors. 68 | 69 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 70 | 71 | http://www.apache.org/licenses/LICENSE-2.0 72 | 73 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 74 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: compile_and_test build run dev shell test 2 | 3 | compile: 4 | swig -c++ -python -py3 Aono.i 5 | python3 setup.py install 6 | 7 | test: 8 | python3 tests.py 9 | 10 | compile_and_test: compile 11 | make test 12 | 13 | # Build the Docker environment 14 | build: 15 | docker build -t openmined/pyaono . 16 | 17 | # Run the source code inside the Docker environment 18 | run: 19 | docker run -i -t openmined/pyaono make test 20 | 21 | # Run *my* source code with the Docker environment 22 | dev: 23 | docker run -i -t -v "$(PWD):/PyAono" openmined/pyaono make compile_and_test 24 | 25 | # Open a shell inside the Docker environment, for debugging 26 | shell: 27 | docker run -i -t -v "$(PWD):/PyAono" openmined/pyaono sh 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyAono [![Build Status](https://travis-ci.org/OpenMined/PyAono.svg?branch=master)](https://travis-ci.org/OpenMined/PyAono) 2 | 3 | ❗ 4 | This library has been deprecated due to changes in strategy and roadmap. To actively contribute based on our current roadmap, checkout [OpenMined](https://github.com/OpenMined/OpenMined), [PySyft](https://github.com/OpenMined/PySyft), or [join our slack](https://openmined.slack.com/messages/team_pysyft) 5 | --- 6 | 7 | 8 | A Python implementation of the homomorphic encryption scheme by Yoshinori Aono et al. 9 | 10 | This scheme was first introduced in the paper - "Fast and Secure Linear Regression and Biometric Authentication with Security Update" by Yoshinori Aono et al. A really unique feature supported by this proposal is the support for key switching. All the code is written in PARI library in C++. 11 | 12 | This code also has an independent header containing a PARI implementation of the Knuth-Yao's Algorithm for sampling from a discrete Gaussian distribution. The paper followed for understanding and implementing the algorithm - High Precision Discrete Gaussian Sampling on FPGAs. 13 | 14 | NOTE : Running the homomorphic multiplication gives a ![equation](http://latex.codecogs.com/gif.latex?%24l*l%24) matrix as opposed to the message being ![equation](http://latex.codecogs.com/gif.latex?%241*l%24). This is because after homomorphic multiplication, we don't get message but we get ![equation](http://latex.codecogs.com/gif.latex?%24m%5ET*m%24). 15 | 16 | ## Running 17 | 18 | 1. Install [Docker](https://www.docker.com/) 19 | 20 | * If you're on macOS and use [Homebrew](https://brew.sh), run `brew cask install docker; open -a docker` 21 | 22 | 2. Run these commands: 23 | 24 | ``` shell 25 | make build 26 | make run 27 | ``` 28 | 29 | ## Development 30 | 31 | 1. Install [Docker](https://www.docker.com/) 32 | 33 | * If you're on macOS and use [Homebrew](https://brew.sh), run `brew cask install docker; open -a docker` 34 | 35 | 2. Run `make build` 36 | 37 | 3. Edit source code as you wish 38 | 39 | 4. Run `make dev` 40 | 41 | ## Notes 42 | 43 | ### What's new in the latest version? 44 | We just rolled out the support for key switching/rotation. Check it out by running `init_key_switching.py`. You can also run `init.py` to check out homomorphic operations working.
45 | This scheme has an `advantage` over other schemes that the key switching can both, increase as well as decrease the security level of the ciphertext! 46 | 47 | ### News 48 | New here? Check out our sample tutorial on YouTube recorded by Mayank. The tutorial covers a basic overview of how to use the API. More in-depth tutorials coming soon. Keep checking out YouTube channel and our GitHub repositories. 49 | 50 | ### Contribute 51 | Welcome! If you are intrigued by our work and want to contribute, then please go through the tutorial as mentioned in the `News` section and contact any of the contributors. You should also go through this introductory video by Andrew Trask, of the OpenMined platform. 52 | 53 | ### Difference between Key Rotation and Security Update 54 | `Key Rotation` means that we change ciphertext associated with the key-pair `(pk1, sk1)`, where `pk1` is used to encrypt the message and `sk1` is used to decrypt to message to another ciphertext associated with keypair `(pk2, sk2)`, without decrypting the first ciphertext.
55 | We specifically call it `Key Rotation` when the parameters have this relation ```n1 = n2```.
56 | We call it `Security Update` if the paramters have this relation ```n1 < n2```, meaning that the security of new ciphertext has been updated and increased. 57 | 58 | ### Notes regarding the use and order of homomorphic function and key switching [`Important`] 59 | The following cases of operations have been implemented. Support for other cases might require some more literature reading and will follow shortly. Please take a look at he following options which are presently supported:
60 | #### `NOTE`: 61 | The scheme only supports `ONE` homomorphic multiplication at the moment.
62 | #### `Notations`: 63 | * `normal-ciphertext` means a ciphertext which has never been refreshed via either key rotation or security update and has only been operated additively or has never undergone any operation is just fresh. 64 | * `mult-ciphertext` means a ciphertext which has undergone `ONE` multiplication no matter if it has undergone key rotation or security update before or not. Note that a `mult-ciphertext` `CANNOT` be rotated or refreshed by key rotation or security update because of it's peculiar structure. It has to be decrypted. 65 | * `rotated-ciphertext` means a ciphertext which has undergone refreshment via either key rotation or security update.
66 | #### `NOTE`: 67 | If `+` is supported it implies `-` is permitted as well.
68 | #### `Permitted operations and their outputs`: 69 | * ``` normal-ciphertext + normal-ciphertext = normal-ciphertext``` and ``` normal-ciphertext * normal-ciphertext = mult-ciphertext``` 70 | * ```mult-ciphertext + mult-ciphertext = mult-ciphertext``` 71 | * ```rotated-ciphertext + rotated-ciphertext = rotated-ciphertext``` and ```rotated-ciphertext * rotated-ciphertext = mult-ciphertext``` 72 | * ```rotated-ciphertext + normal-ciphertext = rotated-ciphertext``` and ```rotated-ciphertext * normal-ciphertext = mult-ciphertext``` 73 | * ```normal-ciphertext + rotated-ciphertext = rotated-ciphertext``` and ```normal-ciphertext * rotated-ciphertext = mult-ciphertext``` 74 | * ```mult-ciphertext + normal-ciphertext = mult-ciphertext``` and ```normal-ciphertext + mult-ciphertext = mult-ciphertext```[?] 75 | * ```mult-ciphertext + rotated-ciphertext = mult-ciphertext``` and ```rotated-ciphertext + mult-ciphertext = mult-ciphertext```[?] 76 | 77 | #### `[?] Meaning`: 78 | The above bullets marked with [?] means that these operations don't exist conventionally in the actual paper. I have implemented them as my own decision given they might come in handy during the course of our project. I implemented them in this way (illustrating just one example, rest are similar to this one):
79 | ```mult-ciphertext + (normal-ciphertext-of-1s * normal-ciphertext) = mult-ciphertext```
80 | `normal-ciphertext-of-1s` mean that it is a ciphertext which is deliberately made my encrypting a vector of just all 1s, so that if it is multiplied with anything (say `x`), this `x` remains same, but since `x` is of type - `normal-ciphertext` and also this `normal-ciphertext-of-1s` is also of the type - `normal-ciphertext`, this means their homomorphic multiplication `*` will yield a ciphertext encrypting `x` of the type - `mult-ciphertext`. This makes the whole above homomorphic addition as ```mult-ciphertext + mult-ciphertext = mult-ciphertext```. 81 | 82 | -------- 83 | 84 | ### Importing API 85 | The API can be imported using the command ```import Aono```. It currently supports the following functions and classes: 86 | 87 | -------- 88 | 89 | ## Functions Supported: 90 | ### 1. ```pari_init(pari_size, max_prime)``` 91 | ```pari_init()``` is the function that needs to be called before dealing with this API. `pari_size` defines the size of stack we'll be using, and `max_prime` defines the pre computed prime table. 92 | #### Arguments: ```pari_size (int)```, ```max_prime (int)``` 93 | ### 2. ```pari_close()``` 94 | ```pari_close()``` function has to be called at the end of each program to clear the memory used. 95 | 96 | -------- 97 | 98 | ## Classes: 99 | ### ```pari_GEN``` 100 | This class abstracts the GEN variable in C++, making it available through python interface. The class is compatible with +, *, /, -, __getitem__ , %, and print. 101 | * Class Data: 102 | 1. `value` (`GEN`) 103 | 104 | * ```__init__(self, x)``` 105 | The constructor converts x to a GEN variable. Arguments: `x` (`int`) 106 | 107 | ### ```parameters``` 108 | * Class Data: 109 | 1. `n`, `s`, `sigma`, `l`, `lambda` (`ints`) 110 | 2. `q`, `p` (`pari_GEN`) 111 | 112 | ### ```secret_key``` 113 | * Class Data: 114 | 1. `sk` (`pari_GEN`) 115 | 2. `params` (`parameters*`) 116 | 117 | * ```__init__(self, sk = None, parmas = None)``` 118 | The constructor initiates class data. 119 | Arguments: `sk` (`pari_GEN`), `params` (`parameters*`) 120 | 121 | * ```decrypt(self, ct)``` 122 | ```decrypt()``` method returns the plaintext (`pari_GEN`) encrypted in ciphertext `ct`. Arguments: `ct` (`pari_GEN`) 123 | 124 | * ```serialize(self)``` 125 | TO BE IMPLEMENTED 126 | 127 | ### ```public_key``` 128 | * Class Data: 129 | 1. `pk` (`public_key_pack*`) 130 | 2. `params` (`parameters*`) 131 | 3. `g` (`globalvars*`) 132 | 133 | * ```__init__(self, pk = None, params = None, g = None)``` 134 | The constructor initiates the class data. 135 | Arguments: `pk` (`public_key_pack*`), `params` (`parameters*`), `g` (`globalvars*`) 136 | 137 | * ```encrypt(self, pt)``` 138 | ```encrypt()``` method returns the ciphertext (`GEN`) which encrypts plaintext `pt`. 139 | Arguments: `pt` (`pari_GEN`) 140 | 141 | * ```serialize(self)``` 142 | TO BE IMPLEMENTED 143 | 144 | ### ```key_pair``` 145 | * Class Data: 146 | 1. `sk` (`secret_key`) 147 | 2. `pk` (`public_key`) 148 | 149 | ### ```key_gen``` 150 | * ```generate_key(self, lambda, l, n, s, sigma, degree_p)``` 151 | ```generate_key()``` method returns the keys, which is of type `key_pair`. Here `s` defines the tailprune and `degree_p` defines the `bit_size` of `p` to be generated. 152 | Arguments: `lambda` (`int`), `l` (`int`), `n` (`int`), `s` (`int`), `sigma` (`int`), `degree_p` (`int`). 153 | 154 | * ```deserialize(self)``` 155 | TO BE IMPLEMENTED 156 | 157 | ### ```ciphertext``` 158 | The class is compatible with `’+’, '*', and '-' operators` 159 | * Class Data: 160 | 1. `value` (`pari_GEN`) 161 | 2. `pk` (`public_key*`) 162 | 3. `params` (`parameters*`) 163 | 164 | * ```__init__(self, plaintext = None, pk, params)``` 165 | The constuctor method takes two arguments: `plaintext` (`pari_GEN` variable), `pk` (`public_key*`), `params` (`parameters*`) 166 | 167 | TODO - Remove `params`, it can be taken from `pk`. 168 | 169 | * ```decrypt(self, sk)``` 170 | ```decrypt()``` method returns the decrypted `ciphertext` which is `pari_GEN` variable. 171 | Arguments: `sk` (`secret_key*`) 172 | 173 | ### ```updation_key``` 174 | * Class Data: 175 | 1. `pk` (`public_key_pack*`) 176 | 2. `params` (`parameters*`) 177 | 3. `old_params` (`parameters*`) 178 | 4. `g` (`globalvars*`) 179 | 5. `XComponent` (`pari_GEN`) 180 | 6. `YComponent` (`pari_GEN`) 181 | 182 | * ```__init__(self, X, Y, params, params_old, g, pk)``` 183 | The constructor initiates the class data. 184 | Arguments: `pk` (`public_key_pack*`), `params` (`parameters*`), `g` (`globalvars*`) 185 | 186 | * ```cipher_switch(self, ciphertext)``` 187 | ```cipher_switch()``` method returns the ciphertext (`ciphertext`) which is obtained by switching the ciphertext passed to function with the updatation key. 188 | Arguments: `ct` (`ciphertext`) 189 | 190 | ### ```updation_key_gen``` 191 | 192 | * ```generate_key(self, key_pair*, key_pair*)``` 193 | ```generate_key()``` method returns the updation key (`updation_key`) which is the key that can be used to switch any ciphertext which is associated with the first (in order of arguments) `key_pair` to the ciphertext which is associated with the second `key_pair`. 194 | Arguments: `key1` (`key_pair`), `key2` (`key_pair`) 195 | 196 | 197 | -------- 198 | 199 | ## TODO: 200 | - [x] Tweaks to homomorphic functions to support rotated or updated ciphertexts.
201 | - [x] Support for plaintext-ciphertext multiplication.
202 | - [x] Basic testing suite.
203 | - [x] Taking care of negative errors by mapping ciphertext to a symmteric group before decryption.
204 | - [x] Add a matrix reading support to testing suite.
205 | - [x] Add key switching tests to testing suite.
206 | - [x] Update README with pari_GEN.
207 | - [ ] Add bootstrapping support.
208 | - [ ] Serialization and Deserialization support.
209 | 210 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | SWIG:Examples:python:class 4 | 5 | 6 | 7 | 8 | 9 | SWIG/Examples/python/class/ 10 |
11 | 12 |

Wrapping a simple C++ class

13 | 14 |

15 | This example illustrates wrapping a simple C++ class to give a Python class. 16 | 17 |

The C++ Code

18 | 19 | Suppose you have some C++ classes described by the following (and admittedly lame) 20 | header file: 21 | 22 |
23 |
 24 | /* File : example.h */
 25 | 
 26 | class Shape {
 27 | public:
 28 |   Shape() {
 29 |     nshapes++;
 30 |   }
 31 |   virtual ~Shape() {
 32 |     nshapes--;
 33 |   }
 34 |   double  x, y;
 35 |   void    move(double dx, double dy);
 36 |   virtual double area() = 0;
 37 |   virtual double perimeter() = 0;
 38 |   static  int nshapes;
 39 | };
 40 | 
 41 | class Circle : public Shape {
 42 | private:
 43 |   double radius;
 44 | public:
 45 |   Circle(double r) : radius(r) { }
 46 |   virtual double area();
 47 |   virtual double perimeter();
 48 | };
 49 | 
 50 | class Square : public Shape {
 51 | private:
 52 |   double width;
 53 | public:
 54 |   Square(double w) : width(w) { }
 55 |   virtual double area();
 56 |   virtual double perimeter();
 57 | };
 58 | 
59 |
60 | 61 |

The SWIG interface

62 | 63 | A simple SWIG interface for this can be built by simply grabbing the header file 64 | like this: 65 | 66 |
67 |
 68 | /* File : example.i */
 69 | %module example
 70 | 
 71 | %{
 72 | #include "example.h"
 73 | %}
 74 | 
 75 | /* Let's just grab the original header file here */
 76 | %include "example.h"
 77 | 
78 |
79 | 80 | Note: when creating a C++ extension, you must run SWIG with the -c++ option like this: 81 |
82 |
 83 | % swig -c++ -python example.i
 84 | 
85 |
86 | 87 |

A sample Python script

88 | 89 | Click here to see a script that calls the C++ functions from Python. 90 | 91 |

Key points

92 | 93 | 142 | 143 |

General Comments

144 | 145 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /init.py: -------------------------------------------------------------------------------- 1 | import Aono 2 | from Aono import * 3 | 4 | pari_init(2000000000, 2) 5 | keys = key_gen() 6 | keys = keys.generate_key(100, 64, 100, 8, 4, 7) 7 | 8 | ct1 = ciphertext(create_message_matrix(4, 64), keys.pk, keys.pk.params) 9 | ct2 = ciphertext(create_message_matrix(5, 64), keys.pk, keys.pk.params) 10 | ct3 = ciphertext(create_message_matrix(6, 64), keys.pk, keys.pk.params) 11 | 12 | run = True 13 | 14 | while run: 15 | 16 | x = input("Press (1, 2, 3, 4, 5 or 6) for next demo: ") 17 | 18 | if x == 1: 19 | print("\n-----------------------------Addition(4+5)---------------------------\n") 20 | ctres = (ct1 + ct2) 21 | print_GEN(get_element(get_element(ctres.decrypt(keys.sk), 0), 0)) 22 | 23 | if x == 2: 24 | print("\n-----------------------------Subtraction(5-4)---------------------------\n") 25 | ctres = (ct2 - ct1) 26 | print_GEN(get_element(get_element(ctres.decrypt(keys.sk), 0), 0)) 27 | 28 | if x == 3: 29 | print("\n-----------------------------Multiplication(4*5)---------------------------\n") 30 | ctres = (ct1 * ct2) 31 | print_GEN(get_element(get_element(ctres.decrypt(keys.sk), 0), 0)) 32 | 33 | if x is 4: 34 | print("\n------------------Nested Addition and Multiplication(((4+5)+5)*6)---------------------------\n") 35 | ctres = ((ct1 + ct2) + ct2 ) * ct3 36 | # first get_element gives the first column and to get the first element, we use another get_element. 37 | print_GEN(get_element(get_element(ctres.decrypt(keys.sk), 0), 0)) 38 | 39 | if x == 5: 40 | print("\n------------------Example ciphertext---------------------------\n") 41 | print_GEN(see_ciphertext(ctres.value, 0)) 42 | 43 | if x == 6: 44 | run = False 45 | 46 | pari_close() 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /init_key_switching.py: -------------------------------------------------------------------------------- 1 | import Aono 2 | from Aono import * 3 | 4 | keysgen = key_gen() 5 | keys1 = keysgen.generate_key(100, 64, 40, 8, 4, 7) 6 | message = 33 7 | print "Plaintext message: " + str(message) 8 | ct = ciphertext(create_message_matrix(message, 64), keys1.pk) 9 | 10 | keys2 = keysgen.generate_key(100, 64, 20, 16, 4, 7) 11 | keys3 = keysgen.generate_key(100, 64, 60, 16, 4, 7) 12 | ukgen = updation_key_gen() 13 | 14 | print "Reducing security with key switching" 15 | uk = ukgen.generate_key(keys1, keys2) 16 | a = uk.cipher_switch(ct) 17 | print "Decrypted message: " 18 | print_GEN(get_element(get_element(a.decrypt(keys2.sk), 0), 0)) 19 | 20 | print "Increasing security with key switching" 21 | uk = ukgen.generate_key(keys1, keys3) 22 | a = uk.cipher_switch(ct) 23 | print "Decrypted message: " 24 | print_GEN(get_element(get_element(a.decrypt(keys3.sk), 0), 0)) 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /init_operations_example.py: -------------------------------------------------------------------------------- 1 | import Aono 2 | from Aono import * 3 | 4 | keysgen = key_gen() 5 | keys1 = keysgen.generate_key(100, 64, 40, 8, 4, 7) 6 | message = 11 7 | print "Plaintext message: " + str(message) 8 | ct = ciphertext(create_message_matrix(message, 64), keys1.pk) 9 | ct1 = ciphertext(create_message_matrix(3, 64), keys1.pk) 10 | keys2 = keysgen.generate_key(100, 64, 20, 16, 4, 7) 11 | keys3 = keysgen.generate_key(100, 64, 60, 16, 4, 7) 12 | ukgen = updation_key_gen() 13 | 14 | print "Reducing security with key switching" 15 | uk = ukgen.generate_key(keys1, keys2) 16 | a = uk.cipher_switch(ct) 17 | print "Decrypted message: " 18 | print_GEN(get_element(get_element(a.decrypt(keys2.sk), 0), 0)) 19 | 20 | print "Increasing security with key switching" 21 | uk = ukgen.generate_key(keys1, keys3) 22 | a = uk.cipher_switch(ct) 23 | print "Decrypted message: " 24 | print_GEN(get_element(get_element(a.decrypt(keys3.sk), 0), 0)) 25 | 26 | uk = ukgen.generate_key(keys1, keys3) 27 | a = uk.cipher_switch(ct) 28 | b = uk.cipher_switch(ct1) 29 | ct = ciphertext(create_message_matrix(4, 64), keys3.pk) 30 | print "Multiplying rotated-ciphertext with normal-ciphetext" 31 | c = a * ct 32 | print_GEN(get_element(get_element(c.decrypt(keys3.sk), 0), 0)) 33 | print "Adding mult-ciphertext with normal-ciphetext" 34 | c1 = c + ct 35 | print_GEN(get_element(get_element(c1.decrypt(keys3.sk), 0), 0)) 36 | print "Adding mult-ciphertext with nested normal-ciphetexts" 37 | c2 = ct + (c1 + ct) 38 | print_GEN(get_element(get_element(c2.decrypt(keys3.sk), 0), 0)) 39 | print "Adding mult-ciphertext with nested rotated-ciphetexts" 40 | c2 = (c1 + a) + a 41 | print_GEN(get_element(get_element(c2.decrypt(keys3.sk), 0), 0)) 42 | print "Adding rotated-ciphertext with normal-ciphetext" 43 | c = (a + ct) 44 | print_GEN(get_element(get_element(c.decrypt(keys3.sk), 0), 0)) 45 | print "Plaintext multiplication and adding rotated-ciphertext with normal-ciphetext" 46 | c = (2 * a) + ct 47 | print_GEN(get_element(get_element(c.decrypt(keys3.sk), 0), 0)) 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /lib/he/basic.h: -------------------------------------------------------------------------------- 1 | #include "keys.h" 2 | 3 | class ciphertext{ 4 | public: 5 | cipher_text* value; 6 | int degree; 7 | public_key* pk; 8 | parameters* params; 9 | 10 | ciphertext(){}; 11 | 12 | ~ciphertext(){}; 13 | 14 | ciphertext(public_key* pk){ 15 | this->degree = 0; 16 | this->pk = pk; 17 | this->params = pk->params; 18 | } 19 | 20 | ciphertext(pari_GEN m, public_key* pk){ 21 | this->degree = 2; 22 | this->pk = pk; 23 | this->value = pk->encrypt(m); 24 | this->params = pk->params; 25 | } 26 | 27 | ciphertext(int m, public_key* pk){ 28 | pari_GEN inp; 29 | inp.value = cgetg(2, t_VEC); 30 | gel(inp.value, 1) = stoi(m); 31 | this->params = pk->params; 32 | pari_GEN messagepacked = create_message_matrix(inp, params->l); 33 | this->degree = 2; 34 | this->pk = pk; 35 | this->value = pk->encrypt(messagepacked); 36 | 37 | } 38 | 39 | ciphertext(cipher_text* ct, public_key* pk){ 40 | this->degree = 2; 41 | this->pk = pk; 42 | this->value = ct; 43 | this->params = pk->params; 44 | } 45 | 46 | void packing_method(pari_GEN m, public_key* pk){ 47 | this->params = pk->params; 48 | pari_GEN messagepacked = create_message_matrix(m, params->l); 49 | this->degree = 2; 50 | this->pk = pk; 51 | this->value = pk->encrypt(messagepacked); 52 | 53 | } 54 | 55 | void initialize(pari_GEN m, public_key* pk){ 56 | this->degree = 2; 57 | this->pk = pk; 58 | this->value = pk->encrypt(m); 59 | this->params = pk->params; 60 | } 61 | 62 | void initialize(public_key* pk){ 63 | this->degree = 0; 64 | this->pk = pk; 65 | this->params = pk->params; 66 | } 67 | 68 | ciphertext operator+(ciphertext &ct){ 69 | ciphertext result; 70 | result.value = addition(this->value, ct.value, params, pk->pk, pk->g); 71 | result.params = params; 72 | result.pk = this->pk; 73 | return result; 74 | } 75 | 76 | ciphertext operator*(ciphertext &ct){ 77 | ciphertext result; 78 | result.value = multiplication(this->value, ct.value, params); 79 | result.params = params; 80 | result.pk = this->pk; 81 | return result; 82 | } 83 | 84 | ciphertext operator*(int input){ 85 | ciphertext result; 86 | pari_GEN inp; 87 | inp.value = stoi(input); 88 | result.value = plaintext_multiplication(this->value, inp); 89 | result.params = params; 90 | result.pk = this->pk; 91 | return result; 92 | } 93 | 94 | ciphertext operator-(ciphertext &ct){ 95 | ciphertext result; 96 | result.value = subtraction(this->value, ct.value, params, pk->pk, pk->g); 97 | result.params = params; 98 | result.pk = this->pk; 99 | return result; 100 | } 101 | 102 | pari_GEN decrypt(secret_key sk){ 103 | pari_GEN m = sk.decrypt(this->value); 104 | return m; 105 | } 106 | }; 107 | 108 | class updation_key{ 109 | private: 110 | pari_GEN X, Y; 111 | public_key* pk; 112 | 113 | public: 114 | parameters* params; 115 | parameters* params_old; 116 | globalvars* g; 117 | 118 | updation_key(){}; 119 | 120 | updation_key(pari_GEN X, pari_GEN Y, parameters* params, parameters* params_old, globalvars* g, public_key* pk){ 121 | this->X = X; 122 | this->Y = Y; 123 | this->params = params; 124 | this->params_old = params_old; 125 | this->g = g; 126 | this->pk = pk; 127 | } 128 | 129 | void initialize(pari_GEN X, pari_GEN Y, parameters* params, parameters* params_old, globalvars* g, public_key* pk){ 130 | this->X = X; 131 | this->Y = Y; 132 | this->params = params; 133 | this->params_old = params_old; 134 | this->g = g; 135 | this->pk = pk; 136 | } 137 | 138 | ciphertext cipher_switch(ciphertext ct){ 139 | GEN A1 = pk->pk->A.value; 140 | GEN P1 = pk->pk->P.value; 141 | GEN c1 = ct.value->comp1.value; 142 | GEN c2 = ct.value->comp2.value; 143 | int kappa = params->lambda+1; 144 | GEN f1, f2, f3, E0, F, cdash; 145 | f1 = zeromatcopy(1, params->n); 146 | for(int i = 1; i <= params->n; i++){ 147 | for(int j=1; j<=1; j++){ 148 | gel(gel(f1, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 149 | } 150 | } 151 | f2 = zeromatcopy(1, params->n); 152 | for(int i = 1; i <= params->n; i++){ 153 | for(int j=1; j<=1; j++){ 154 | gel(gel(f2, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 155 | } 156 | } 157 | f3 = zeromatcopy(1, params->l); 158 | for(int i = 1; i <= params->l; i++){ 159 | for(int j=1; j<=1; j++){ 160 | gel(gel(f3, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 161 | } 162 | } 163 | E0 = gadd(gmul(f1, appendmat(A1, P1, params->n, params->l, params->n)), gmul(params->p.value, appendmat(f2, f3, params->n, params->l, 1))); 164 | GEN bitsc1 = bits(c1, kappa, params_old->n); 165 | GEN tempcal = gmul(bitsc1, X.value); 166 | 167 | F = appendmat(tempcal, gadd(gmul(bits(c1, kappa, params_old->n), Y.value), c2), params->n, params->l, 1); 168 | 169 | cdash = gadd(E0, F); 170 | cipher_text* ctret = new cipher_text; 171 | pari_GEN cdashret, comp2ret; 172 | cdashret.value = cdash; 173 | comp2ret.value = stoi(0); 174 | ctret->comp1 = cdashret; 175 | ctret->comp2 = comp2ret; 176 | ctret->flag = 3; 177 | ciphertext cp = ciphertext(ctret, pk); 178 | return cp; 179 | } 180 | 181 | void serialize(){ 182 | return; 183 | } 184 | 185 | ~updation_key(){}; 186 | }; 187 | 188 | class updation_key_gen{ 189 | public: 190 | updation_key_gen(){}; 191 | 192 | updation_key generate_key(key_pair* key1, key_pair* key2){ 193 | 194 | secret_key sk1 = key1->sk; 195 | secret_key sk2 = key2->sk; 196 | public_key pk1 = key1->pk; 197 | public_key pk2 = key2->pk; 198 | parameters* params1 = pk1.params; 199 | parameters* params2 = pk2.params; 200 | GEN S1, S2, A1, A2, P1, P2; 201 | int n1, n2, s1, s2; 202 | S1 = sk1.sk.value; 203 | S2 = sk2.sk.value; 204 | A1 = pk1.pk->A.value; 205 | A2 = pk2.pk->A.value; 206 | P1 = pk1.pk->P.value; 207 | P2 = pk2.pk->P.value; 208 | n1 = params1->n; 209 | s1 = params1->s; 210 | n2 = params2->n; 211 | s2 = params2->s; 212 | int kappa = params1->lambda+1; 213 | 214 | GEN X, E, Y; 215 | X = zeromatcopy(itos(gmul(stoi(n1),stoi(kappa))), n2); 216 | long long int nkappa = itos(gmul(stoi(n1),stoi(kappa))); 217 | for(int i = 1; i <= n2; i++){ 218 | for(int j=1; j<=nkappa; j++){ 219 | gel(gel(X, i), j) = gmodulo(generate_random(params1->lambda).value, params1->q.value); 220 | } 221 | } 222 | E = zeromatcopy(nkappa, params1->l); 223 | for(int i = 1; i <= params1->l; i++){ 224 | for(int j=1; j<=nkappa; j++){ 225 | gel(gel(E, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params2, pk1.g)), stoi(s2))); 226 | } 227 | } 228 | 229 | Y = gsub(gadd(gmul(params1->p.value, E), power2(S1, n1, kappa, params1->l, params1->q.value)), gmul(X, S2)); 230 | pari_GEN xret, yret; 231 | xret.value = X; 232 | yret.value = Y; 233 | updation_key updated_key = updation_key(xret, yret, params2, params1, pk1.g, &key2->pk); 234 | return updated_key; 235 | } 236 | }; 237 | 238 | -------------------------------------------------------------------------------- /lib/he/keys.h: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | class secret_key{ 4 | private: 5 | pari_GEN sk; 6 | 7 | public: 8 | parameters* params; 9 | 10 | secret_key(){}; 11 | 12 | secret_key(pari_GEN sk, parameters* params){ 13 | this->sk = sk; 14 | this->params = params; 15 | } 16 | 17 | void initialize(pari_GEN sk, parameters* params){ 18 | this->sk = sk; 19 | this->params = params; 20 | } 21 | 22 | pari_GEN decrypt(cipher_text* ct){ 23 | GEN m; 24 | if(ct->flag==1){ 25 | m = lift(gadd(gmul(ct->comp1.value, sk.value), ct->comp2.value)); 26 | for(int i=1; i<=lg(m)-1; i++){ 27 | for(int j=1; j<=lg(gel(m, 1))-1; j++){ 28 | if(gcmp(gmul(stoi(2), gel(gel(m, i), j)), params->q.value) == 1){ 29 | gel(gel(m, i), j) = gsub(gel(gel(m, i), j), params->q.value); 30 | } 31 | } 32 | } 33 | m = lift(gmodulo(m, params->p.value)); 34 | } 35 | 36 | else if(ct->flag==2){ 37 | GEN SIMatrix = zeromatcopy(params->n+params->l, params->l); 38 | GEN I = matid(params->l); 39 | for(int i = 1; i <= params->l; i++){ 40 | for(int j=1; j<=params->l+params->n; j++){ 41 | if(j<=params->n){ 42 | gel(gel(SIMatrix, i), j) = gel(gel(sk.value, i), j); 43 | 44 | } 45 | else{ 46 | gel(gel(SIMatrix, i), j) = gel(gel(I, i), j-params->n); 47 | } 48 | } 49 | } 50 | 51 | m = lift(gmul(RgM_transmul(SIMatrix, ct->comp1.value), SIMatrix)); 52 | 53 | for(int i=1; i<=lg(m)-1; i++){ 54 | for(int j=1; j<=lg(gel(m, 1))-1; j++){ 55 | if(gcmp(gmul(stoi(2), gel(gel(m, i), j)), params->q.value) == 1){ 56 | gel(gel(m, i), j) = gsub(gel(gel(m, i), j), params->q.value); 57 | } 58 | } 59 | } 60 | m = lift(gmodulo(m, params->p.value)); 61 | 62 | } 63 | else{ 64 | GEN SIMatrix = zeromatcopy(params->n+params->l, params->l); 65 | GEN I = matid(params->l); 66 | for(int i = 1; i <= params->l; i++){ 67 | for(int j=1; j<=params->l+params->n; j++){ 68 | if(j<=params->n){ 69 | gel(gel(SIMatrix, i), j) = gel(gel(sk.value, i), j); 70 | 71 | } 72 | else{ 73 | gel(gel(SIMatrix, i), j) = gel(gel(I, i), j-params->n); 74 | } 75 | } 76 | } 77 | m = lift(gmul(ct->comp1.value, SIMatrix)); 78 | for(int i=1; i<=lg(m)-1; i++){ 79 | for(int j=1; j<=lg(gel(m, 1))-1; j++){ 80 | if(gcmp(gmul(stoi(2), gel(gel(m, i), j)), params->q.value) == 1){ 81 | gel(gel(m, i), j) = gsub(gel(gel(m, i), j), params->q.value); 82 | } 83 | } 84 | } 85 | m = lift(gmodulo(m, params->p.value)); 86 | } 87 | pari_GEN mret; 88 | mret.value = m; 89 | return mret; 90 | } 91 | 92 | void serialize(){ 93 | return; 94 | } 95 | friend class updation_key_gen; 96 | 97 | ~secret_key(){}; 98 | }; 99 | 100 | class public_key{ 101 | private: 102 | public_key_pack* pk; 103 | 104 | public: 105 | parameters* params; 106 | globalvars* g; 107 | 108 | public_key(){}; 109 | 110 | public_key(public_key_pack* pk, parameters* params, globalvars* g){ 111 | this->pk = pk; 112 | this->params = params; 113 | this->g = g; 114 | } 115 | 116 | void initialize(public_key_pack* pk, parameters* params, globalvars* g){ 117 | this->pk = pk; 118 | this->params = params; 119 | this->g = g; 120 | } 121 | 122 | cipher_text* encrypt(pari_GEN m){ 123 | GEN e1 = zeromatcopy(1, params->n); 124 | GEN e2 = zeromatcopy(1, params->n); 125 | GEN e3 = zeromatcopy(1, params->l); 126 | 127 | for(int i = 1; i <= params->n; i++){ 128 | for(int j=1; j<=1; j++){ 129 | gel(gel(e1, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 130 | gel(gel(e2, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 131 | } 132 | } 133 | for(int i = 1; i <= params->l; i++){ 134 | for(int j=1; j<=1; j++){ 135 | gel(gel(e3, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 136 | } 137 | } 138 | pari_GEN c1, c2; 139 | c1.value = gadd(RgM_mul(e1, pk->A.value), gmul(params->p.value, e2)); 140 | c2.value = gadd(gadd(RgM_mul(e1, pk->P.value), gmul(params->p.value, e3)), m.value); 141 | cipher_text* ct = new cipher_text; 142 | ct->comp1 = c1; 143 | ct->comp2 = c2; 144 | return ct; 145 | } 146 | 147 | void serialize(){ 148 | return; 149 | } 150 | 151 | friend class updation_key_gen; 152 | friend class updation_key; 153 | friend class ciphertext; 154 | 155 | ~public_key(){}; 156 | }; 157 | 158 | struct key_pair{ 159 | secret_key sk; 160 | public_key pk; 161 | }; 162 | 163 | class key_gen{ 164 | public: 165 | key_gen(){}; 166 | 167 | key_pair generate_key(int lambda, int l, int n, int s, int sigma, int degree_p){ 168 | key_pair keys; 169 | parameters* params = new parameters; 170 | pari_GEN p, q; 171 | q.value = nextprime(gpowgs(stoi(2), lambda)); 172 | p.value = gadd(gpowgs(stoi(2), degree_p), stoi(1)); 173 | params->p = p; 174 | params->q = q; 175 | params->lambda = lambda; 176 | params->l = l; 177 | params->s = s; 178 | params->n = n; 179 | params->sigma = sigma; 180 | 181 | globalvars* g = initialize_sampler(params); 182 | 183 | pari_GEN temp = generate_secret_key(params, g); 184 | keys.sk.initialize(temp, params); 185 | public_key_pack* temp1 = generate_public_key(temp, params, g); 186 | keys.pk.initialize(temp1, params, g); 187 | return keys; 188 | } 189 | 190 | }; 191 | 192 | -------------------------------------------------------------------------------- /lib/he/knuthYaoSampler.h: -------------------------------------------------------------------------------- 1 | // 2 | // knuthYaoSampler.h 3 | // AonoEnc 4 | // 5 | // Created by Mayank Rathee on 25/08/17. 6 | // Copyright © 2017 Mayank Rathee. All rights reserved. 7 | // 8 | 9 | #ifndef M_PI 10 | #define M_PI 3.14159265358979323846 11 | #endif 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #define PARI_OLD_NAMES 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | 25 | struct ProbMatrixPack{ 26 | GEN P; 27 | vector startPos; 28 | } *pPacklocal; 29 | 30 | ProbMatrixPack* pPack = new ProbMatrixPack; 31 | 32 | 33 | //mulir(sinv, gexp( gdiv(gneg(gpow(gdiv(gsub(point, center), sigma), stoi(2), precision)), strtor("2.00", precision)), precision)); 34 | 35 | GEN getGuassProbability(GEN point, GEN sigma, GEN center, int precision){ 36 | GEN twopi = mulir(stoi(2), mppi(precision)); 37 | GEN s = mulir(sigma, sqrtr(twopi)); 38 | GEN sinv = invr(s); 39 | 40 | // if point is 0 41 | if(gcmp(point, strtor("0.00", precision)) == 0) 42 | return sinv; 43 | else{ 44 | return gmul(sinv, gexp( gdiv(gneg(gpow(gdiv(gsub(point, center), sigma), stoi(2), precision)), strtor("2.00", precision)), precision)); 45 | } 46 | } 47 | 48 | // Function to generate the probability matrix which is a substitute of the DDT Tree. Some really fine optimizations are not considered here which help prune this matrix 49 | 50 | ProbMatrixPack* getProbabilityMatrix(int sigma, char* c, int precision, int tailprune){ 51 | GEN center; 52 | center = strtor(c, precision); 53 | 54 | GEN tempP, beginAddressP, ProbofPoints; 55 | int bounds = tailprune*sigma; 56 | // Now Points will run in [-bound, bound]. Since, all the points here except 0 will have 2 occurences, one of positive side and one on negative side (like x and -x). So, the probablility of 0 will be reduced to half later in this function 57 | // We consider only the positive points along with 0 (with half probability) 58 | ProbofPoints = cgetg(bounds+2, t_REAL); // extra 1 for 0 59 | // For a 64-bit machine the number of bits in long is 64 60 | int bitprecision = 64*(precision-2); 61 | cout<<"Knuth Yao Probability matrix is moving forward with a bit precision of "< 0; x--){ 75 | gel(ProbofPoints, bounds+1-x) = getGuassProbability(gadd(center, stoi(x)), stoi(sigma), center, precision); 76 | } 77 | // We have found the probability for the rest of points except the point x = 0, which will have 1/2 probability because it does not have a negative counterpart. 78 | gel(ProbofPoints, bounds+1) = gdiv(getGuassProbability(gadd(center, stoi(0)), stoi(sigma), center, precision), stoi(2)); 79 | 80 | int i = -1; 81 | for(int j=0; j= 0; x--){ 85 | gel(gel(tempP, j+1), bounds+1-x) = stoi(0); 86 | if(gcmp(gel(ProbofPoints, bounds+1-x), temppow) >= 0){ 87 | gel(gel(tempP, j+1), bounds+1-x) = stoi(1); 88 | gel(ProbofPoints, bounds+1-x) = gsub(gel(ProbofPoints, bounds+1-x), temppow); 89 | } 90 | } 91 | } 92 | 93 | //cout<= 0; x--){ 96 | for(int j=0; j beginPos; 103 | 104 | for(int x = bounds; x >= 0; x--){ 105 | for(int j=0; jP = tempP; 119 | pPack->startPos = beginPos; 120 | 121 | 122 | 123 | //pPack = pPacklocal; 124 | return pPack; 125 | // Some part remaining 126 | 127 | } 128 | 129 | int SampleKnuthYao(int tailprune, int sigma, int c, int precision){ 130 | GEN center; 131 | center = stoi(c); 132 | 133 | int bounds, col, d, invsample, pRows, pCols, s, flag, enable, hit; 134 | unsigned long r; 135 | bounds = tailprune*sigma; 136 | d = 0; 137 | hit = 0; 138 | invsample = bounds+1; 139 | 140 | //ProbMatrixPack* pPack = getProbabilityMatrix(4, "3.455555554534535353253425234543534535345245235312345678901234567890", 6, 4); 141 | 142 | GEN P = pPack->P; 143 | vector beginPos = pPack->startPos; 144 | int bitprecision = 64*(precision-2); 145 | pRows = lg(P)-1; 146 | pCols = bitprecision; 147 | 148 | flag = 1-2*(rand()%2); // Requires change in the PRNG. A stronger one is required. 149 | 150 | int randomBits[pRows]; 151 | int length = sizeof(unsigned long)*8; 152 | 153 | 154 | for(int i=0; i 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #define PARI_OLD_NAMES 11 | #include 12 | #include 13 | #include 14 | 15 | #define precision 6 // This means 256-bit precision 16 | 17 | struct timeval tv; 18 | 19 | class pari_GEN{ 20 | public: 21 | GEN value; 22 | 23 | pari_GEN(){}; 24 | 25 | pari_GEN(int x){ 26 | value = stoi(x); 27 | return; 28 | } 29 | 30 | void initialize(GEN x){ 31 | value = x; 32 | return; 33 | } 34 | 35 | pari_GEN operator+(const pari_GEN GEN_2){ 36 | pari_GEN result; 37 | result.value = gadd(this->value, GEN_2.value); 38 | return result; 39 | } 40 | 41 | pari_GEN operator*(const pari_GEN GEN_2){ 42 | pari_GEN result; 43 | result.value = gmul(this->value, GEN_2.value); 44 | return result; 45 | } 46 | 47 | pari_GEN operator/(const pari_GEN GEN_2){ 48 | pari_GEN result; 49 | result.value = gdiv(this->value, GEN_2.value); 50 | return result; 51 | } 52 | 53 | pari_GEN operator-(const pari_GEN GEN_2){ 54 | pari_GEN result; 55 | result.value = gsub(this->value, GEN_2.value); 56 | return result; 57 | } 58 | 59 | pari_GEN operator%(const pari_GEN GEN_2){ 60 | pari_GEN result; 61 | result.value = gmodulo(this->value, GEN_2.value); 62 | return result; 63 | } 64 | 65 | bool operator==(const pari_GEN GEN_2){ 66 | if(!gequal(this->value, GEN_2.value)) 67 | return false; 68 | else 69 | return true; 70 | } 71 | }; 72 | 73 | struct parameters{ 74 | pari_GEN q, p; 75 | int lambda; 76 | int l; 77 | int s, n; // These are changed during rotation 78 | int sigma; 79 | }; 80 | 81 | struct ProbMatrixPack{ 82 | pari_GEN P; 83 | std::vector startPos; 84 | bool isInitialized = false; 85 | } *pPackglobal; 86 | 87 | struct public_key_pack{ 88 | pari_GEN A; 89 | pari_GEN P; 90 | int n, s; 91 | }; 92 | 93 | struct globalvars{ 94 | ProbMatrixPack* pPack; 95 | int errorsModulo = 20; 96 | }; 97 | 98 | struct cipher_text{ 99 | int flag = 1; 100 | pari_GEN comp1, comp2; 101 | }; 102 | 103 | struct cipher_text_mult{ 104 | int flag = 2; 105 | pari_GEN c; 106 | }; 107 | 108 | GEN get_element(pari_GEN x, int index){ 109 | return gel(x.value, index + 1); 110 | } 111 | 112 | GEN get_element(GEN x, int index){ 113 | return gel(x, index + 1); 114 | } 115 | 116 | void print_GEN(pari_GEN x){ 117 | printf("%s\n", GENtostr(x.value)); 118 | } 119 | 120 | void print_GEN(GEN x){ 121 | printf("%s\n", GENtostr(x)); 122 | } 123 | 124 | GEN create_GEN(int x){ 125 | GEN y = stoi(x); 126 | return y; 127 | } 128 | 129 | GEN create_GEN(char* x){ 130 | GEN y = strtor(x, precision); 131 | return y; 132 | } 133 | 134 | GEN create_GEN(int m, int n){ // Creates a GEN mxn matrix with all 0s 135 | GEN y = zeromatcopy(m, n); 136 | return y; 137 | } 138 | 139 | double Uniform(void) { 140 | return ((double) rand() + 1.0) / ((double) RAND_MAX + 2.0); 141 | } 142 | 143 | double Normal(void) { 144 | return sqrt(-log(Uniform())*2.0) * sin(2.0 * M_PI * Uniform()); 145 | } 146 | 147 | double Gauss(double mu, double sigma) { 148 | double z = sqrt(-2.0 * log(Uniform())) * sin(2.0 * M_PI * Uniform()); 149 | return mu + sigma*z; 150 | } 151 | 152 | pari_GEN Sample(int n, double sigma) { 153 | pari_GEN ret; 154 | ret.value = cgetg(n + 1, t_VEC); 155 | double z; 156 | int i; 157 | 158 | for (i = 1; i <= n; i++) { 159 | z = Gauss(0, sigma); 160 | z = fabs(round(z)); /*absolute value of Gaussian distribution */ 161 | ret.value[i] = (long) stoi((long) z); 162 | } 163 | 164 | return ret; 165 | } 166 | 167 | pari_GEN generate_random(int bit_length){ 168 | gettimeofday(&tv, NULL); 169 | setrand(stoi(tv.tv_usec + tv.tv_sec*1000000)); 170 | pari_GEN r; 171 | r.value = randomi(gshift(gen_1, bit_length)); 172 | return r; 173 | } 174 | 175 | GEN getGuassProbability(GEN point, GEN center, parameters* params){ 176 | int sigma = params->sigma; 177 | GEN twopi = mulir(stoi(2), mppi(precision)); 178 | GEN s = mulir(stoi(sigma), sqrtr(twopi)); 179 | GEN sinv = invr(s); 180 | if(gcmp(point, strtor("0.00", precision)) == 0) 181 | return sinv; 182 | else{ 183 | return gmul(sinv, gexp( gdiv(gneg(gpow(gdiv(gsub(point, center), stoi(sigma)), stoi(2), precision)), strtor("2.00", precision)), precision)); 184 | } 185 | } 186 | 187 | ProbMatrixPack* genProbabilityMatrix(parameters* params, char* c){ 188 | int sigma = params->sigma; 189 | int tailprune = params->s; 190 | GEN center; 191 | center = strtor(c, precision); 192 | 193 | GEN tempP, beginAddressP, ProbofPoints; 194 | int bounds = tailprune*sigma; 195 | ProbofPoints = cgetg(bounds+2, t_REAL); 196 | int bitprecision = 64*(precision-2); 197 | tempP = cgetg(bitprecision+1, t_VEC); 198 | for(int i=1; i<=bitprecision; i++){ 199 | GEN temp = cgetg(bounds+2, t_INT); 200 | gel(tempP, i) = temp; 201 | } 202 | for(int x = bounds; x > 0; x--){ 203 | gel(ProbofPoints, bounds+1-x) = getGuassProbability(gadd(center, stoi(x)), center, params); 204 | } 205 | gel(ProbofPoints, bounds+1) = gdiv(getGuassProbability(gadd(center, stoi(0)), center, params), stoi(2)); 206 | 207 | int i = -1; 208 | for(int j=0; j= 0; x--){ 212 | gel(gel(tempP, j+1), bounds+1-x) = stoi(0); 213 | if(gcmp(gel(ProbofPoints, bounds+1-x), temppow) >= 0){ 214 | gel(gel(tempP, j+1), bounds+1-x) = stoi(1); 215 | gel(ProbofPoints, bounds+1-x) = gsub(gel(ProbofPoints, bounds+1-x), temppow); 216 | } 217 | } 218 | } 219 | 220 | std::vector beginPos; 221 | 222 | for(int x = bounds; x >= 0; x--){ 223 | for(int j=0; jP = P; 239 | pPack->startPos = beginPos; 240 | pPack->isInitialized = true; 241 | pPackglobal = pPack; 242 | return pPack; 243 | 244 | } 245 | 246 | ProbMatrixPack* genProbabilityMatrix(parameters* params, int c){ 247 | int sigma = params->sigma; 248 | int tailprune = params->s; 249 | GEN center; 250 | center = stoi(c); 251 | 252 | GEN tempP, beginAddressP, ProbofPoints; 253 | int bounds = tailprune*sigma; 254 | ProbofPoints = cgetg(bounds+2, t_REAL); 255 | int bitprecision = 64*(precision-2); 256 | tempP = cgetg(bitprecision+1, t_VEC); 257 | for(int i=1; i<=bitprecision; i++){ 258 | GEN temp = cgetg(bounds+2, t_INT); 259 | gel(tempP, i) = temp; 260 | } 261 | for(int x = bounds; x > 0; x--){ 262 | gel(ProbofPoints, bounds+1-x) = getGuassProbability(gadd(center, stoi(x)), center, params); 263 | } 264 | gel(ProbofPoints, bounds+1) = gdiv(getGuassProbability(gadd(center, stoi(0)), center, params), stoi(2)); 265 | 266 | 267 | int i = -1; 268 | for(int j=0; j= 0; x--){ 272 | gel(gel(tempP, j+1), bounds+1-x) = stoi(0); 273 | if(gcmp(gel(ProbofPoints, bounds+1-x), temppow) >= 0){ 274 | gel(gel(tempP, j+1), bounds+1-x) = stoi(1); 275 | gel(ProbofPoints, bounds+1-x) = gsub(gel(ProbofPoints, bounds+1-x), temppow); 276 | } 277 | } 278 | } 279 | 280 | std::vector beginPos; 281 | 282 | for(int x = bounds; x >= 0; x--){ 283 | for(int j=0; jP = P; 299 | pPack->startPos = beginPos; 300 | pPack->isInitialized = true; 301 | pPackglobal = pPack; 302 | return pPack; 303 | 304 | } 305 | 306 | int SampleKnuthYao(int c, parameters* params, globalvars* g){ 307 | int sigma = params->sigma; 308 | int tailprune = params->s; 309 | GEN center; 310 | center = stoi(c); 311 | 312 | int bounds, col, d, invsample, pRows, pCols, s, flag, enable, hit; 313 | unsigned long r; 314 | bounds = tailprune*sigma; 315 | d = 0; 316 | hit = 0; 317 | invsample = bounds+1; 318 | 319 | GEN P = g->pPack->P.value; 320 | std::vector beginPos = g->pPack->startPos; 321 | int bitprecision = 64*(precision-2); 322 | pRows = lg(P)-1; 323 | pCols = bitprecision; 324 | 325 | flag = 1-2*(rand()%2); 326 | 327 | int randomBits[pRows]; 328 | int length = sizeof(unsigned long)*8; 329 | 330 | 331 | for(int i=0; ipPack = genProbabilityMatrix(params, "0.00"); 359 | return g; 360 | } 361 | 362 | globalvars* initialize_sampler(parameters* params, int center){ 363 | globalvars* g = new globalvars; 364 | g->pPack = genProbabilityMatrix(params, center); 365 | return g; 366 | } 367 | 368 | void getGENsize(GEN x){ 369 | printf("%d\n", lg(x)-1); 370 | } 371 | 372 | void getGEN_MATRIXsize(GEN x){ 373 | printf("%dx%d\n", lg(gel(x, 1))-1, lg(x)-1); 374 | } 375 | 376 | pari_GEN generate_secret_key(parameters* params, globalvars* g){ 377 | if(g->pPack->isInitialized == false){ 378 | g = initialize_sampler(params); 379 | } 380 | GEN q = params->q.value; 381 | GEN p = params->p.value; 382 | int lambda = params->lambda; 383 | int l = params->l; 384 | int s = params->s; 385 | int n = params->n; 386 | GEN S; 387 | S = zeromatcopy(n, l); 388 | 389 | for(int i = 1; i <= l; i++){ 390 | for(int j=1; j<=n; j++){ 391 | gel(gel(S, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(s))); 392 | } 393 | } 394 | pari_GEN Sret; 395 | Sret.value = S; 396 | return Sret; 397 | } 398 | 399 | pari_GEN generate_secret_key(parameters* params, int center, globalvars* g){ 400 | if(g->pPack->isInitialized == false){ 401 | g = initialize_sampler(params, center); 402 | } 403 | GEN q = params->q.value; 404 | GEN p = params->p.value; 405 | int lambda = params->lambda; 406 | int l = params->l; 407 | int s = params->s; 408 | int n = params->n; 409 | GEN S; 410 | S = zeromatcopy(n, l); 411 | 412 | for(int i = 1; i <= l; i++){ 413 | for(int j=1; j<=n; j++){ 414 | gel(gel(S, i), j) = lift(gmodulo(stoi(SampleKnuthYao(center, params, g)), stoi(s))); 415 | } 416 | } 417 | pari_GEN Sret; 418 | Sret.value = S; 419 | return Sret; 420 | } 421 | 422 | public_key_pack* generate_public_key(pari_GEN sk, parameters* params, globalvars* g){ 423 | if(g->pPack->isInitialized == false){ 424 | g = initialize_sampler(params); 425 | } 426 | GEN q = params->q.value; 427 | GEN p = params->p.value; 428 | int lambda = params->lambda; 429 | int l = params->l; 430 | int s = params->s; 431 | int n = params->n; 432 | int modulo = g->errorsModulo; 433 | 434 | GEN S = sk.value; 435 | 436 | GEN R, A; 437 | R = zeromatcopy(n, l); 438 | 439 | for(int i = 1; i <= l; i++){ 440 | for(int j=1; j<=n; j++){ 441 | gel(gel(R, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(s))); 442 | } 443 | } 444 | A = zeromatcopy(n, n); 445 | for(int i = 1; i <= n; i++){ 446 | for(int j=1; j<=n; j++){ 447 | gel(gel(A, i), j) = gmodulo(generate_random(params->lambda).value, q); 448 | } 449 | } 450 | 451 | GEN P, temp; 452 | temp = RgM_mul(A, S); 453 | P = gsub(gmul(p, R), temp); 454 | 455 | public_key_pack* pk = new public_key_pack; 456 | pari_GEN Pret, Aret; 457 | Pret.value = P; 458 | Aret.value = A; 459 | pk->P = Pret; 460 | pk->A = Aret; 461 | pk->n = n; 462 | pk->s = s; 463 | return pk; 464 | } 465 | 466 | public_key_pack* generate_public_key(pari_GEN sk, parameters* params, globalvars* g, int center){ 467 | if(g->pPack->isInitialized == false){ 468 | g = initialize_sampler(params); 469 | } 470 | GEN q = params->q.value; 471 | GEN p = params->p.value; 472 | int lambda = params->lambda; 473 | int l = params->l; 474 | int s = params->s; 475 | int n = params->n; 476 | int modulo = g->errorsModulo; 477 | 478 | GEN S = sk.value; 479 | 480 | GEN R, A; 481 | R = zeromatcopy(n, l); 482 | 483 | for(int i = 1; i <= l; i++){ 484 | for(int j=1; j<=n; j++){ 485 | gel(gel(R, i), j) = lift(gmodulo(stoi(SampleKnuthYao(center, params, g)), stoi(s))); 486 | } 487 | } 488 | A = zeromatcopy(n, n); 489 | for(int i = 1; i <= n; i++){ 490 | for(int j=1; j<=n; j++){ 491 | gel(gel(A, i), j) = gmodulo(generate_random(params->lambda).value, q); 492 | } 493 | } 494 | 495 | GEN P, temp; 496 | temp = RgM_mul(A, S); 497 | P = gsub(gmul(p, R), temp); 498 | 499 | public_key_pack* pk = new public_key_pack; 500 | pari_GEN Pret, Aret; 501 | Pret.value = P; 502 | Aret.value = A; 503 | pk->P = Pret; 504 | pk->A = Aret; 505 | pk->n = n; 506 | pk->s = s; 507 | return pk; 508 | } 509 | 510 | 511 | globalvars* set_error_modulo(globalvars* g, int modulo){ 512 | g->errorsModulo = modulo; 513 | return g; 514 | } 515 | 516 | GEN access_value_pk(public_key_pack* pk, char flag){ 517 | if(flag == 'a' || flag == 'A'){ 518 | return pk->A.value; 519 | } 520 | else if(flag == 'p' || flag == 'P'){ 521 | return pk->P.value; 522 | } 523 | else if(flag == 'n' || flag == 'N'){ 524 | return stoi(pk->n); 525 | } 526 | else if(flag == 's' || flag == 'S'){ 527 | return stoi(pk->s); 528 | } 529 | else 530 | return stoi(0); 531 | } 532 | 533 | parameters* gen_params(int lambda, int l, int n, int s, int sigma, int degree_p){ 534 | GEN q = nextprime(gpowgs(stoi(2), lambda)); 535 | GEN p = gadd(gpowgs(stoi(2), degree_p), stoi(1)); 536 | parameters* params = new parameters; 537 | pari_GEN pret, qret; 538 | pret.value = p; 539 | qret.value = q; 540 | params->p = pret; 541 | params->q = qret; 542 | params->lambda = lambda; 543 | params->l = l; 544 | params->s = s; 545 | params->n = n; // These are changed during rotation 546 | params->sigma = sigma; 547 | return params; 548 | } 549 | 550 | pari_GEN create_message_matrix_repeated_input(int , int ); 551 | cipher_text* multiplication(cipher_text* , cipher_text* , parameters* ); 552 | 553 | cipher_text* encrypt_outside_class(pari_GEN m, public_key_pack* pk, parameters* params, globalvars* g){ 554 | GEN e1 = zeromatcopy(1, params->n); 555 | GEN e2 = zeromatcopy(1, params->n); 556 | GEN e3 = zeromatcopy(1, params->l); 557 | 558 | for(int i = 1; i <= params->n; i++){ 559 | for(int j=1; j<=1; j++){ 560 | gel(gel(e1, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 561 | gel(gel(e2, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 562 | } 563 | } 564 | for(int i = 1; i <= params->l; i++){ 565 | for(int j=1; j<=1; j++){ 566 | gel(gel(e3, i), j) = lift(gmodulo(stoi(SampleKnuthYao(0, params, g)), stoi(params->s))); 567 | } 568 | } 569 | pari_GEN c1, c2; 570 | c1.value = gadd(RgM_mul(e1, pk->A.value), gmul(params->p.value, e2)); 571 | c2.value = gadd(gadd(RgM_mul(e1, pk->P.value), gmul(params->p.value, e3)), m.value); 572 | cipher_text* ct = new cipher_text; 573 | ct->comp1 = c1; 574 | ct->comp2 = c2; 575 | return ct; 576 | } 577 | 578 | cipher_text* addition(cipher_text* ct_1, cipher_text* ct_2, parameters* params, public_key_pack* pk, globalvars* g){ 579 | if (ct_1->flag == 1 && ct_2->flag == 2){ 580 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 581 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 582 | 583 | cipher_text* newct = multiplication(one_enc, ct_1, params); 584 | GEN ct1, ct2; 585 | ct1 = gadd(newct->comp1.value, ct_2->comp1.value); 586 | cipher_text* ct = new cipher_text; 587 | pari_GEN comp1ret, comp2ret; 588 | comp1ret.value = ct1; 589 | comp2ret.value = stoi(0); 590 | ct->comp1 = comp1ret; 591 | ct->comp2 = comp2ret; 592 | ct->flag = 2; 593 | return ct; 594 | } 595 | else if (ct_1->flag == 2 && ct_2->flag == 1){ 596 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 597 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 598 | 599 | cipher_text* newct = multiplication(one_enc, ct_2, params); 600 | GEN ct1, ct2; 601 | ct1 = gadd(ct_1->comp1.value, newct->comp1.value); 602 | cipher_text* ct = new cipher_text; 603 | pari_GEN comp1ret, comp2ret; 604 | comp1ret.value = ct1; 605 | comp2ret.value = stoi(0); 606 | ct->comp1 = comp1ret; 607 | ct->comp2 = comp2ret; 608 | ct->flag = 2; 609 | return ct; 610 | } 611 | else if (ct_1->flag == 3 && ct_2->flag == 2){ 612 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 613 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 614 | 615 | cipher_text* newct = multiplication(one_enc, ct_1, params); 616 | GEN ct1, ct2; 617 | ct1 = gadd(newct->comp1.value, ct_2->comp1.value); 618 | cipher_text* ct = new cipher_text; 619 | pari_GEN comp1ret, comp2ret; 620 | comp1ret.value = ct1; 621 | comp2ret.value = stoi(0); 622 | ct->comp1 = comp1ret; 623 | ct->comp2 = comp2ret; 624 | ct->flag = 2; 625 | return ct; 626 | } 627 | else if (ct_1->flag == 2 && ct_2->flag == 3){ 628 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 629 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 630 | 631 | cipher_text* newct = multiplication(one_enc, ct_2, params); 632 | GEN ct1, ct2; 633 | ct1 = gadd(ct_1->comp1.value, newct->comp1.value); 634 | cipher_text* ct = new cipher_text; 635 | pari_GEN comp1ret, comp2ret; 636 | comp1ret.value = ct1; 637 | comp2ret.value = stoi(0); 638 | ct->comp1 = comp1ret; 639 | ct->comp2 = comp2ret; 640 | ct->flag = 2; 641 | return ct; 642 | } 643 | else if (ct_1->flag == 2 && ct_2->flag == 2){ 644 | GEN ct1, ct2; 645 | ct1 = gadd(ct_1->comp1.value, ct_2->comp1.value); 646 | cipher_text* ct = new cipher_text; 647 | pari_GEN comp1ret, comp2ret; 648 | comp1ret.value = ct1; 649 | comp2ret.value = stoi(0); 650 | ct->comp1 = comp1ret; 651 | ct->comp2 = comp2ret; 652 | ct->flag = 2; 653 | return ct; 654 | } 655 | else if (ct_1->flag == 3 && ct_2->flag == 3){ 656 | GEN ct1, ct2; 657 | ct1 = gadd(ct_1->comp1.value, ct_2->comp1.value); 658 | cipher_text* ct = new cipher_text; 659 | pari_GEN comp1ret, comp2ret; 660 | comp1ret.value = ct1; 661 | comp2ret.value = stoi(0); 662 | ct->comp1 = comp1ret; 663 | ct->comp2 = comp2ret; 664 | ct->flag = 3; 665 | return ct; 666 | } 667 | else if (ct_1->flag == 3 && ct_2->flag == 1){ 668 | GEN q = params->q.value; 669 | GEN p = params->p.value; 670 | int lambda = params->lambda; 671 | int l = params->l; 672 | int s = params->s; 673 | int n = params->n; 674 | int nplusl = n+l; 675 | GEN c2changed = zeromatcopy(1, nplusl); 676 | for(int i = 1; i <= nplusl; i++){ 677 | for(int j=1; j<=1; j++){ 678 | if(i<=n){ 679 | gel(gel(c2changed, i), j) = gel(gel(ct_2->comp1.value, i), j); 680 | 681 | } 682 | else{ 683 | gel(gel(c2changed, i), j) = gel(gel(ct_2->comp2.value, i-n), j); 684 | } 685 | } 686 | } 687 | 688 | GEN ct1, ct2; 689 | ct1 = gadd(ct_1->comp1.value, c2changed); 690 | cipher_text* ct = new cipher_text; 691 | pari_GEN comp1ret, comp2ret; 692 | comp1ret.value = ct1; 693 | comp2ret.value = stoi(0); 694 | ct->comp1 = comp1ret; 695 | ct->comp2 = comp2ret; 696 | ct->flag = 3; 697 | return ct; 698 | } 699 | else if (ct_1->flag == 1 && ct_2->flag == 3){ 700 | GEN q = params->q.value; 701 | GEN p = params->p.value; 702 | int lambda = params->lambda; 703 | int l = params->l; 704 | int s = params->s; 705 | int n = params->n; 706 | int nplusl = n+l; 707 | GEN c1changed = zeromatcopy(1, nplusl); 708 | for(int i = 1; i <= nplusl; i++){ 709 | for(int j=1; j<=1; j++){ 710 | if(i<=n){ 711 | gel(gel(c1changed, i), j) = gel(gel(ct_1->comp1.value, i), j); 712 | 713 | } 714 | else{ 715 | gel(gel(c1changed, i), j) = gel(gel(ct_1->comp2.value, i-n), j); 716 | } 717 | } 718 | } 719 | 720 | GEN ct1, ct2; 721 | ct1 = gadd(ct_2->comp1.value, c1changed); 722 | cipher_text* ct = new cipher_text; 723 | pari_GEN comp1ret, comp2ret; 724 | comp1ret.value = ct1; 725 | comp2ret.value = stoi(0); 726 | ct->comp1 = comp1ret; 727 | ct->comp2 = comp2ret; 728 | ct->flag = 3; 729 | return ct; 730 | } 731 | else{ 732 | GEN ct1, ct2; 733 | ct1 = gadd(ct_1->comp1.value, ct_2->comp1.value); 734 | ct2 = gadd(ct_1->comp2.value, ct_2->comp2.value); 735 | cipher_text* ct = new cipher_text; 736 | pari_GEN comp1ret, comp2ret; 737 | comp1ret.value = ct1; 738 | comp2ret.value = ct2; 739 | ct->comp1 = comp1ret; 740 | ct->comp2 = comp2ret; 741 | return ct; 742 | } 743 | } 744 | 745 | cipher_text* subtraction(cipher_text* ct_1, cipher_text* ct_2, parameters* params, public_key_pack* pk, globalvars* g){ 746 | if (ct_1->flag == 1 && ct_2->flag == 2){ 747 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 748 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 749 | 750 | cipher_text* newct = multiplication(one_enc, ct_1, params); 751 | GEN ct1, ct2; 752 | ct1 = gsub(newct->comp1.value, ct_2->comp1.value); 753 | cipher_text* ct = new cipher_text; 754 | pari_GEN comp1ret, comp2ret; 755 | comp1ret.value = ct1; 756 | comp2ret.value = stoi(0); 757 | ct->comp1 = comp1ret; 758 | ct->comp2 = comp2ret; 759 | ct->flag = 2; 760 | return ct; 761 | } 762 | else if (ct_1->flag == 2 && ct_2->flag == 1){ 763 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 764 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 765 | 766 | cipher_text* newct = multiplication(one_enc, ct_2, params); 767 | GEN ct1, ct2; 768 | ct1 = gsub(ct_1->comp1.value, newct->comp1.value); 769 | cipher_text* ct = new cipher_text; 770 | pari_GEN comp1ret, comp2ret; 771 | comp1ret.value = ct1; 772 | comp2ret.value = stoi(0); 773 | ct->comp1 = comp1ret; 774 | ct->comp2 = comp2ret; 775 | ct->flag = 2; 776 | return ct; 777 | } 778 | else if (ct_1->flag == 3 && ct_2->flag == 2){ 779 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 780 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 781 | 782 | cipher_text* newct = multiplication(one_enc, ct_1, params); 783 | GEN ct1, ct2; 784 | ct1 = gsub(newct->comp1.value, ct_2->comp1.value); 785 | cipher_text* ct = new cipher_text; 786 | pari_GEN comp1ret, comp2ret; 787 | comp1ret.value = ct1; 788 | comp2ret.value = stoi(0); 789 | ct->comp1 = comp1ret; 790 | ct->comp2 = comp2ret; 791 | ct->flag = 2; 792 | return ct; 793 | } 794 | else if (ct_1->flag == 2 && ct_2->flag == 3){ 795 | pari_GEN messagemat = create_message_matrix_repeated_input(1, params->l); 796 | cipher_text* one_enc = encrypt_outside_class(messagemat, pk, params, g); 797 | 798 | cipher_text* newct = multiplication(one_enc, ct_2, params); 799 | GEN ct1, ct2; 800 | ct1 = gsub(ct_1->comp1.value, newct->comp1.value); 801 | cipher_text* ct = new cipher_text; 802 | pari_GEN comp1ret, comp2ret; 803 | comp1ret.value = ct1; 804 | comp2ret.value = stoi(0); 805 | ct->comp1 = comp1ret; 806 | ct->comp2 = comp2ret; 807 | ct->flag = 2; 808 | return ct; 809 | } 810 | else if (ct_1->flag == 2 && ct_2->flag == 2){ 811 | GEN ct1, ct2; 812 | ct1 = gsub(ct_1->comp1.value, ct_2->comp1.value); 813 | cipher_text* ct = new cipher_text; 814 | pari_GEN comp1ret, comp2ret; 815 | comp1ret.value = ct1; 816 | comp2ret.value = stoi(0); 817 | ct->comp1 = comp1ret; 818 | ct->comp2 = comp2ret; 819 | ct->flag = 2; 820 | return ct; 821 | } 822 | else if (ct_1->flag == 3 && ct_2->flag == 3){ 823 | GEN ct1, ct2; 824 | ct1 = gsub(ct_1->comp1.value, ct_2->comp1.value); 825 | cipher_text* ct = new cipher_text; 826 | pari_GEN comp1ret, comp2ret; 827 | comp1ret.value = ct1; 828 | comp2ret.value = stoi(0); 829 | ct->comp1 = comp1ret; 830 | ct->comp2 = comp2ret; 831 | ct->flag = 3; 832 | return ct; 833 | } 834 | else if (ct_1->flag == 3 && ct_2->flag == 1){ 835 | GEN q = params->q.value; 836 | GEN p = params->p.value; 837 | int lambda = params->lambda; 838 | int l = params->l; 839 | int s = params->s; 840 | int n = params->n; 841 | int nplusl = n+l; 842 | GEN c2changed = zeromatcopy(1, nplusl); 843 | for(int i = 1; i <= nplusl; i++){ 844 | for(int j=1; j<=1; j++){ 845 | if(i<=n){ 846 | gel(gel(c2changed, i), j) = gel(gel(ct_2->comp1.value, i), j); 847 | 848 | } 849 | else{ 850 | gel(gel(c2changed, i), j) = gel(gel(ct_2->comp2.value, i-n), j); 851 | } 852 | } 853 | } 854 | 855 | GEN ct1, ct2; 856 | ct1 = gsub(ct_1->comp1.value, c2changed); 857 | cipher_text* ct = new cipher_text; 858 | pari_GEN comp1ret, comp2ret; 859 | comp1ret.value = ct1; 860 | comp2ret.value = stoi(0); 861 | ct->comp1 = comp1ret; 862 | ct->comp2 = comp2ret; 863 | ct->flag = 3; 864 | return ct; 865 | } 866 | else if (ct_1->flag == 1 && ct_2->flag == 3){ 867 | GEN q = params->q.value; 868 | GEN p = params->p.value; 869 | int lambda = params->lambda; 870 | int l = params->l; 871 | int s = params->s; 872 | int n = params->n; 873 | int nplusl = n+l; 874 | GEN c1changed = zeromatcopy(1, nplusl); 875 | for(int i = 1; i <= nplusl; i++){ 876 | for(int j=1; j<=1; j++){ 877 | if(i<=n){ 878 | gel(gel(c1changed, i), j) = gel(gel(ct_1->comp1.value, i), j); 879 | 880 | } 881 | else{ 882 | gel(gel(c1changed, i), j) = gel(gel(ct_1->comp2.value, i-n), j); 883 | } 884 | } 885 | } 886 | 887 | GEN ct1, ct2; 888 | ct1 = gsub(c1changed, ct_2->comp1.value); 889 | cipher_text* ct = new cipher_text; 890 | pari_GEN comp1ret, comp2ret; 891 | comp1ret.value = ct1; 892 | comp2ret.value = stoi(0); 893 | ct->comp1 = comp1ret; 894 | ct->comp2 = comp2ret; 895 | ct->flag = 3; 896 | return ct; 897 | } 898 | else{ 899 | GEN ct1, ct2; 900 | ct1 = gsub(ct_1->comp1.value, ct_2->comp1.value); 901 | ct2 = gsub(ct_1->comp2.value, ct_2->comp2.value); 902 | cipher_text* ct = new cipher_text; 903 | pari_GEN comp1ret, comp2ret; 904 | comp1ret.value = ct1; 905 | comp2ret.value = ct2; 906 | ct->comp1 = comp1ret; 907 | ct->comp2 = comp2ret; 908 | return ct; 909 | } 910 | } 911 | 912 | 913 | cipher_text* multiplication(cipher_text* ct_1, cipher_text* ct_2, parameters* params){ 914 | GEN q = params->q.value; 915 | GEN p = params->p.value; 916 | int lambda = params->lambda; 917 | int l = params->l; 918 | int s = params->s; 919 | int n = params->n; 920 | int nplusl = n+l; 921 | 922 | if (ct_1->flag == 3 && ct_2->flag == 3){ 923 | GEN cbeforemul = ct_1->comp1.value; 924 | GEN c_1beforemul = ct_2->comp1.value; 925 | 926 | GEN cmul = RgM_transmul(cbeforemul, c_1beforemul); 927 | cipher_text* ret = new cipher_text; 928 | pari_GEN comp1ret, comp2ret; 929 | comp1ret.value = cmul; 930 | comp2ret.value = stoi(0); 931 | ret->comp1 = comp1ret; 932 | ret->comp2 = comp2ret; 933 | ret->flag = 2; 934 | return ret; 935 | } 936 | else if (ct_1->flag == 3 && ct_2->flag == 1){ 937 | GEN cbeforemul = ct_1->comp1.value; 938 | GEN c_1beforemul = zeromatcopy(1, nplusl); 939 | for(int i = 1; i <= nplusl; i++){ 940 | for(int j=1; j<=1; j++){ 941 | if(i<=n){ 942 | gel(gel(c_1beforemul, i), j) = gel(gel(ct_2->comp1.value, i), j); 943 | 944 | } 945 | else{ 946 | gel(gel(c_1beforemul, i), j) = gel(gel(ct_2->comp2.value, i-n), j); 947 | } 948 | } 949 | } 950 | 951 | GEN cmul = RgM_transmul(cbeforemul, c_1beforemul); 952 | cipher_text* ret = new cipher_text; 953 | pari_GEN comp1ret, comp2ret; 954 | comp1ret.value = cmul; 955 | comp2ret.value = stoi(0); 956 | ret->comp1 = comp1ret; 957 | ret->comp2 = comp2ret; 958 | ret->flag = 2; 959 | return ret; 960 | } 961 | else if (ct_1->flag == 1 && ct_2->flag == 3){ 962 | GEN cbeforemul = zeromatcopy(1, nplusl); 963 | GEN c_1beforemul = ct_2->comp1.value; 964 | for(int i = 1; i <= nplusl; i++){ 965 | for(int j=1; j<=1; j++){ 966 | if(i<=n){ 967 | gel(gel(cbeforemul, i), j) = gel(gel(ct_1->comp1.value, i), j); 968 | 969 | } 970 | else{ 971 | gel(gel(cbeforemul, i), j) = gel(gel(ct_1->comp2.value, i-n), j); 972 | 973 | } 974 | } 975 | } 976 | 977 | GEN cmul = RgM_transmul(cbeforemul, c_1beforemul); 978 | cipher_text* ret = new cipher_text; 979 | pari_GEN comp1ret, comp2ret; 980 | comp1ret.value = cmul; 981 | comp2ret.value = stoi(0); 982 | ret->comp1 = comp1ret; 983 | ret->comp2 = comp2ret; 984 | ret->flag = 2; 985 | return ret; 986 | } 987 | else{ 988 | GEN cbeforemul = zeromatcopy(1, nplusl); 989 | GEN c_1beforemul = zeromatcopy(1, nplusl); 990 | for(int i = 1; i <= nplusl; i++){ 991 | for(int j=1; j<=1; j++){ 992 | if(i<=n){ 993 | gel(gel(cbeforemul, i), j) = gel(gel(ct_1->comp1.value, i), j); 994 | gel(gel(c_1beforemul, i), j) = gel(gel(ct_2->comp1.value, i), j); 995 | 996 | } 997 | else{ 998 | gel(gel(cbeforemul, i), j) = gel(gel(ct_1->comp2.value, i-n), j); 999 | gel(gel(c_1beforemul, i), j) = gel(gel(ct_2->comp2.value, i-n), j); 1000 | } 1001 | } 1002 | } 1003 | 1004 | GEN cmul = RgM_transmul(cbeforemul, c_1beforemul); 1005 | cipher_text* ret = new cipher_text; 1006 | pari_GEN comp1ret, comp2ret; 1007 | comp1ret.value = cmul; 1008 | comp2ret.value = stoi(0); 1009 | ret->comp1 = comp1ret; 1010 | ret->comp2 = comp2ret; 1011 | ret->flag = 2; 1012 | return ret; 1013 | } 1014 | } 1015 | 1016 | pari_GEN create_message_matrix(int message, int l){ 1017 | GEN m = zeromatcopy(1, l); 1018 | gel(gel(m, 1), 1) = stoi(message); 1019 | pari_GEN ret; 1020 | ret.value = m; 1021 | return ret; 1022 | } 1023 | 1024 | pari_GEN create_message_matrix_repeated_input(int message, int l){ 1025 | GEN m = zeromatcopy(1, l); 1026 | for(int i = 1; i <= l; i++){ 1027 | for(int j=1; j<=1; j++){ 1028 | gel(gel(m, i), j) = stoi(message); 1029 | } 1030 | } 1031 | pari_GEN ret; 1032 | ret.value = m; 1033 | return ret; 1034 | } 1035 | 1036 | pari_GEN create_message_matrix(pari_GEN message, int l){ 1037 | GEN m = zeromatcopy(1, l); 1038 | for(int i = 1; i <= l; i++){ 1039 | for(int j=1; j<=1; j++){ 1040 | if (i>lg(message.value)-1){ 1041 | gel(gel(m, i), j) = stoi(0); 1042 | } 1043 | else{ 1044 | gel(gel(m, i), j) = gel(message.value, i); 1045 | } 1046 | } 1047 | } 1048 | pari_GEN ret; 1049 | ret.value = m; 1050 | return ret; 1051 | } 1052 | 1053 | GEN see_ciphertext(cipher_text* c, int index){ 1054 | if(index == 0) 1055 | return c->comp1.value; 1056 | else 1057 | return c->comp2.value; 1058 | } 1059 | 1060 | GEN power2(GEN x, int n, int kappa, int l, GEN q){ 1061 | GEN power2mat = zeromatcopy(n*kappa, l); 1062 | long long int nkappa = n*kappa; 1063 | GEN pow2 = stoi(1); 1064 | for(int i = 1; i <= l; i++){ 1065 | pow2 = stoi(1); 1066 | for(int j=1; j <= kappa; j++){ 1067 | for(int k=1; k<=n; k++){ 1068 | gel(gel(power2mat, i), (j-1)*n+k) = gmodulo(gmul(gel(gel(x, i), k), pow2), q); 1069 | } 1070 | pow2 = gmul(pow2, stoi(2)); 1071 | } 1072 | } 1073 | 1074 | return power2mat; 1075 | } 1076 | 1077 | GEN appendmat(GEN m1, GEN m2, int col1, int col2, int row){ 1078 | GEN mat = zeromatcopy(row, col1+col2); 1079 | for(int i =1; i<= col1+col2; i++){ 1080 | for(int j=1; j<=row; j++){ 1081 | if(i<=col1){ 1082 | gel(gel(mat, i), j) = gel(gel(m1, i), j); 1083 | } 1084 | else{ 1085 | gel(gel(mat, i), j) = gel(gel(m2, i-col1), j); 1086 | } 1087 | } 1088 | } 1089 | 1090 | return mat; 1091 | } 1092 | 1093 | GEN bits(GEN m, int kappa, int n){ 1094 | GEN mat = zeromatcopy(1, n*kappa); 1095 | long long int nkappa = n*kappa; 1096 | for(int i =1; i<= n; i++){ 1097 | GEN bintemp = binary_zv(lift(gel(gel(m, i), 1))); 1098 | bintemp = gtovec(bintemp); 1099 | GEN binx = cgetg(lg(bintemp), t_VEC); 1100 | for(int j=1; j<=lg(bintemp)-1; j++){ 1101 | gel(binx, j) = gel(bintemp, lg(bintemp)-j); 1102 | } 1103 | int size = lg(binx)-1; 1104 | for(int j=1; j<=kappa; j++){ 1105 | if(j>size){ 1106 | gel(gel(mat, i+(j-1)*n), 1) = stoi(0); 1107 | } 1108 | else{ 1109 | gel(gel(mat, i+(j-1)*n), 1) = gel(binx, j); 1110 | } 1111 | } 1112 | } 1113 | 1114 | return mat; 1115 | } 1116 | 1117 | parameters* get_updation_parameters(parameters* params_old, int n, int s){ 1118 | parameters* params = new parameters; 1119 | params->n = n; 1120 | params->s = s; 1121 | params->q = params_old->q; 1122 | params->p = params_old->p; 1123 | params->lambda = params_old->lambda; 1124 | params->l = params_old->l; 1125 | params->sigma = params_old->sigma; 1126 | return params; 1127 | 1128 | } 1129 | 1130 | cipher_text* plaintext_multiplication(cipher_text* ct, pari_GEN input){ 1131 | cipher_text* ret = new cipher_text; 1132 | pari_GEN comp1ret, comp2ret; 1133 | comp1ret.value = gmul(ct->comp1.value, input.value); 1134 | comp2ret.value = gmul(ct->comp2.value, input.value); 1135 | ret->comp1 = comp1ret; 1136 | ret->comp2 = comp2ret; 1137 | ret->flag = ct->flag; 1138 | return ret; 1139 | } 1140 | 1141 | 1142 | 1143 | 1144 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | 4 | example_module = Extension('_Aono', 5 | sources=['Aono_wrap.cxx'], 6 | swig_opts=['-c++'], 7 | include_dirs = ['/usr/local/include/'], 8 | library_dirs = ['/usr/local/lib/'], 9 | libraries = ['pari'], 10 | # extra_compile_args = ["-std=c++11", "-lpari", "-mmacosx-version-min=10.7", "-pthread", "-O3", "-march=native", "-Wall", "-funroll-loops", "-Wno-unused-result","-I/usr/local/opt/openblas/include/"], 11 | extra_compile_args = ["-std=c++11", "-pthread", "-O3", "-march=native", "-Wall", "-funroll-loops", "-Wno-unused-result", "-lpari"], 12 | ) 13 | 14 | setup (name = 'Aono', 15 | version = '0.2', 16 | author = "SWIG Docs", 17 | description = """Simple swig linguamind from docs""", 18 | ext_modules = [example_module], 19 | py_modules = ["Aono"], 20 | ) 21 | -------------------------------------------------------------------------------- /tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import Aono 3 | 4 | class correctness_test(unittest.TestCase): 5 | def __init__(self, *args, **kwargs): 6 | super(correctness_test, self).__init__(*args, **kwargs) 7 | keys = Aono.key_gen() 8 | self.keys = keys.generate_key(100, 64, 40, 8, 4, 7) 9 | 10 | def test_single_data(self): 11 | ct = Aono.ciphertext(5, self.keys.pk) 12 | pt = Aono.pari_GEN(5) 13 | self.assertEqual(ct.decrypt(self.keys.sk)[0][0], pt) 14 | 15 | def test_multiple_data(self): 16 | ct = Aono.ciphertext([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], self.keys.pk) 17 | pt = Aono.pari_GEN([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 18 | self.assertEqual(ct.decrypt(self.keys.sk).sub_mat_array(0, 10), pt) 19 | 20 | class addition_test(unittest.TestCase): 21 | def __init__(self, *args, **kwargs): 22 | super(addition_test, self).__init__(*args, **kwargs) 23 | keys = Aono.key_gen() 24 | self.keys = keys.generate_key(100, 64, 40, 8, 4, 7) 25 | 26 | def test_single_data(self): 27 | ct_1 = Aono.ciphertext(10, self.keys.pk) 28 | ct_2 = Aono.ciphertext(5, self.keys.pk) 29 | pt = Aono.pari_GEN(15) 30 | ct = ct_1 + ct_2 31 | self.assertEqual(ct.decrypt(self.keys.sk)[0][0], pt) 32 | 33 | def test_multiple_data(self): 34 | ct_1 = Aono.ciphertext([1, 2, 3, 4, 5], self.keys.pk) 35 | ct_2 = Aono.ciphertext([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], self.keys.pk) 36 | pt = Aono.pari_GEN([2, 4, 6, 8, 10, 6, 7, 8, 9, 10]) 37 | ct = ct_1 + ct_2 38 | self.assertEqual(ct.decrypt(self.keys.sk).sub_mat_array(0, 10), pt) 39 | 40 | class subtraction_test(unittest.TestCase): 41 | def __init__(self, *args, **kwargs): 42 | super(subtraction_test, self).__init__(*args, **kwargs) 43 | keys = Aono.key_gen() 44 | self.keys = keys.generate_key(100, 64, 40, 8, 4, 7) 45 | 46 | def test_single_data(self): 47 | ct_1 = Aono.ciphertext(10, self.keys.pk) 48 | ct_2 = Aono.ciphertext(5, self.keys.pk) 49 | pt = Aono.pari_GEN(5) 50 | ct = ct_1 - ct_2 51 | self.assertEqual(ct.decrypt(self.keys.sk)[0][0], pt) 52 | 53 | def test_multiple_data(self): 54 | ct_1 = Aono.ciphertext([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], self.keys.pk) 55 | ct_2 = Aono.ciphertext([1, 2, 3, 4, 5], self.keys.pk) 56 | pt = Aono.pari_GEN([0, 0, 0, 0, 0, 6, 7, 8, 9, 10]) 57 | ct = ct_1 - ct_2 58 | self.assertEqual(ct.decrypt(self.keys.sk).sub_mat_array(0, 10), pt) 59 | 60 | 61 | class miscellaneous(unittest.TestCase): 62 | def __init__(self, *args, **kwargs): 63 | super(miscellaneous, self).__init__(*args, **kwargs) 64 | keys = Aono.key_gen() 65 | self.keys = keys.generate_key(100, 64, 40, 8, 4, 7) 66 | 67 | def test_ciphertext_array(self): 68 | ciphertext_array = [] 69 | for i in range(1, 10): 70 | ciphertext_array.append(Aono.ciphertext(i, self.keys.pk)) 71 | pt = Aono.pari_GEN(5) 72 | self.assertEqual(ciphertext_array[4].decrypt(self.keys.sk)[0][0], pt) 73 | 74 | def test_nested_operations(self): 75 | ct_1 = Aono.ciphertext(3, self.keys.pk) 76 | ct_2 = Aono.ciphertext(4, self.keys.pk) 77 | pt = Aono.pari_GEN(38) 78 | ct = 2 * ((ct_1 * ct_2) + (ct_1 + ct_2)) 79 | self.assertEqual(ct.decrypt(self.keys.sk)[0][0], pt) 80 | 81 | class multiplication_test(unittest.TestCase): 82 | def __init__(self, *args, **kwargs): 83 | super(multiplication_test, self).__init__(*args, **kwargs) 84 | keys = Aono.key_gen() 85 | self.keys = keys.generate_key(100, 64, 40, 8, 4, 7) 86 | 87 | def test_single_data(self): 88 | ct_1 = Aono.ciphertext(10, self.keys.pk) 89 | ct_2 = Aono.ciphertext(5, self.keys.pk) 90 | pt = Aono.pari_GEN(50) 91 | ct = ct_1 * ct_2 92 | self.assertEqual(ct.decrypt(self.keys.sk)[0][0], pt) 93 | 94 | def test_multiple_data(self): 95 | ct_1 = Aono.ciphertext([1, 2, 3, 4, 5], self.keys.pk) 96 | ct_2 = Aono.ciphertext([1, 2, 3, 4, 5], self.keys.pk) 97 | pt = Aono.pari_GEN([[1,2,3,4,5],[2,4,6,8,10],[3,6,9,12,15],[4,8,12,16,20],[5,10,15,20,25]]) 98 | ct = ct_1 * ct_2 99 | self.assertEqual(ct.decrypt(self.keys.sk).sub_mat_array(0, 5, 0, 5), pt) 100 | 101 | def test_single_data_plaintext(self): 102 | ct = Aono.ciphertext(10, self.keys.pk) 103 | pt = Aono.pari_GEN(40) 104 | ct_1 = ct * 4 105 | ct_2 = 4 * ct 106 | self.assertEqual(ct_1.decrypt(self.keys.sk)[0][0], pt) 107 | self.assertEqual(ct_1.decrypt(self.keys.sk)[0][0], pt) 108 | 109 | def test_multiple_data_plaintext(self): 110 | ct = Aono.ciphertext([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], self.keys.pk) 111 | pt = Aono.pari_GEN([4, 8, 12, 16, 20, 24, 28, 32, 36, 40]) 112 | ct_1 = ct * 4 113 | ct_2 = 4 * ct 114 | self.assertEqual(ct_1.decrypt(self.keys.sk).sub_mat_array(0, 10), pt) 115 | self.assertEqual(ct_2.decrypt(self.keys.sk).sub_mat_array(0, 10), pt) 116 | 117 | class keyswitching_test(unittest.TestCase): 118 | def __init__(self, *args, **kwargs): 119 | super(keyswitching_test, self).__init__(*args, **kwargs) 120 | self.keysgen = Aono.key_gen() 121 | self.keys = self.keysgen.generate_key(100, 64, 20, 8, 4, 7) 122 | self.keys2 = self.keysgen.generate_key(100, 64, 10, 16, 4, 7) 123 | self.keys3 = self.keysgen.generate_key(100, 64, 25, 8, 4, 7) 124 | self.updatingkey = Aono.updation_key_gen() 125 | self.ukey1 = self.updatingkey.generate_key(self.keys, self.keys2) 126 | self.ukey2 = self.updatingkey.generate_key(self.keys, self.keys3) 127 | 128 | def test_single_data_decrease_security(self): 129 | ct = Aono.ciphertext(5, self.keys.pk) 130 | ctupdated = self.ukey1.cipher_switch(ct) 131 | pt = Aono.pari_GEN(5) 132 | self.assertEqual(ctupdated.decrypt(self.keys2.sk)[0][0], pt) 133 | 134 | def test_single_data_increase_security(self): 135 | ct = Aono.ciphertext(5, self.keys.pk) 136 | ctupdated = self.ukey2.cipher_switch(ct) 137 | pt = Aono.pari_GEN(5) 138 | self.assertEqual(ctupdated.decrypt(self.keys3.sk)[0][0], pt) 139 | 140 | def test_multiple_data_increase_security(self): 141 | ct = Aono.ciphertext([5,4,3,2,1], self.keys.pk) 142 | ctupdated = self.ukey2.cipher_switch(ct) 143 | pt = Aono.pari_GEN([5,4,3,2,1]) 144 | self.assertEqual(ctupdated.decrypt(self.keys3.sk).sub_mat_array(0, 5), pt) 145 | 146 | def test_single_data_multiplication(self): 147 | ct1 = Aono.ciphertext(5, self.keys.pk) 148 | ct2 = Aono.ciphertext(4, self.keys3.pk) 149 | ctupdated = self.ukey2.cipher_switch(ct1) 150 | pt = Aono.pari_GEN(20) 151 | ct = ctupdated * ct2 152 | self.assertEqual(ct.decrypt(self.keys3.sk)[0][0], pt) 153 | ct = 5 * ctupdated 154 | pt = Aono.pari_GEN(25) 155 | self.assertEqual(ct.decrypt(self.keys3.sk)[0][0], pt) 156 | 157 | def test_single_data_addition(self): 158 | ct1 = Aono.ciphertext(5, self.keys.pk) 159 | ct2 = Aono.ciphertext(4, self.keys3.pk) 160 | ct3 = Aono.ciphertext(6, self.keys3.pk) 161 | ctupdated = self.ukey2.cipher_switch(ct1) 162 | pt = Aono.pari_GEN(9) 163 | ct = ctupdated + ct2 164 | self.assertEqual(ct.decrypt(self.keys3.sk)[0][0], pt) 165 | ctmul = ct2 * ct3 166 | ct = ctmul + ctupdated 167 | pt = Aono.pari_GEN(29) 168 | self.assertEqual(ct.decrypt(self.keys3.sk)[0][0], pt) 169 | ct = (2 * ctupdated) + ct2 170 | pt = Aono.pari_GEN(14) 171 | self.assertEqual(ct.decrypt(self.keys3.sk)[0][0], pt) 172 | 173 | def test_multiple_data_addition(self): 174 | ct1 = Aono.ciphertext([5,4,3,2], self.keys.pk) 175 | ct2 = Aono.ciphertext([4,3,2,1], self.keys3.pk) 176 | ct3 = Aono.ciphertext([6,5,4,3], self.keys3.pk) 177 | ctupdated = self.ukey2.cipher_switch(ct1) 178 | pt = Aono.pari_GEN([9,7,5,3]) 179 | ct = ctupdated + ct2 180 | self.assertEqual(ct.decrypt(self.keys3.sk).sub_mat_array(0, 4), pt) 181 | ct = 2 * ( 2 * ctupdated + ct2 ) 182 | pt = Aono.pari_GEN([28,22,16,10]) 183 | self.assertEqual(ct.decrypt(self.keys3.sk).sub_mat_array(0, 4), pt) 184 | 185 | 186 | if __name__ == '__main__': 187 | unittest.main() 188 | 189 | --------------------------------------------------------------------------------