ibarrond / Pyfhel

PYthon For Homomorphic Encryption Libraries, perform encrypted computations such as sum, mult, scalar product or matrix multiplication in Python, with NumPy compatibility. Uses SEAL/PALISADE as backends, implemented using Cython.
https://pyfhel.readthedocs.io/
Apache License 2.0
475 stars 78 forks source link

BufferError: scalar buffer is readonly #209

Closed Samirakamali closed 1 year ago

Samirakamali commented 1 year ago

Description Hi. I am would like to use Pyfhel 3.4.1 for my project. I were using Pyfhel 2.3.1 on colab and everything was ok,however after updating colab, It dosent work. After using other version i have encountered following error on this part of my work. how can I fix it?

def encrypt_export_weights(indx):
    HE = get_pk()
    model = load_weights(str(indx+1))
    start = time.time()
    encrypted_weights={}
    for i in range(len(model.layers)):
        if model.layers[i].get_weights()!=[]:
            encrypted =[]
            weights = model.layers[i].get_weights()

            for j in range(len(weights)):
                    weight = weights[j]
                    shape = weight.shape
                    weight = weight.flatten()
                    array= np.empty(len(weight),dtype=PyCtxt)
                    #ptxt1 = HE.encodeFrac(array)
                    #ctxt1 = HE.encryptPtxt(ptxt1)

                    for k in np.arange(len(weight)):
                        array[k] = HE.encryptFrac(weight[k])

                    enc_array = array.reshape(shape)
                    #enc_array = np.array(enc_array,dtype=PyCtxt)
                    encrypted_weights['c_'+str(i)+'_'+str(j)]=enc_array

    end = time.time()
    print('Time to encrypt weights:',end-start)
    filename =  "weights/client_" + str(indx+1)+ ".pickle"
    export_weights(filename, encrypted_weights)

    ...................................................................................................
    <ipython-input-26-416ea1813273> in export_encrypted_clients_weights(num_client)
    151     start = time.time()
    152     for i in range(num_client):
--> 153         encrypt_export_weights(i)
    154         print('Weights exported: Client',i+1)
    155     end = time.time()

<ipython-input-26-416ea1813273> in encrypt_export_weights(indx)
    123 
    124                     for k in np.arange(len(weight)):
--> 125                         array[k] = HE.encryptFrac(weight[k])
    126 
    127                     enc_array = array.reshape(shape)

Pyfhel/Pyfhel.pyx in Pyfhel.Pyfhel.Pyfhel.encryptFrac()

/usr/local/lib/python3.10/dist-packages/Pyfhel/Pyfhel.cpython-310-x86_64-linux-gnu.so in View.MemoryView.memoryview_cwrapper()

/usr/local/lib/python3.10/dist-packages/Pyfhel/Pyfhel.cpython-310-x86_64-linux-gnu.so in View.MemoryView.memoryview.__cinit__()

**BufferError: scalar buffer is readonly**
.................................................................................................................................................................................

Setup:

ShokofehVS commented 1 year ago

Hi Samira, maybe this issue can help you find the solution. I understood that you are trying to encrypt each individual element in the vector (i.e., weight) which somehow is overkill and increase your time performance. Instead, you can find out how efficient approach is encrypting for instance a 2-D matrix once (i.e, SIMD feature in CKKS scheme).

ibarrond commented 1 year ago

As hinted by @ShokofehVS , this issue has already been addressed (#151). Version 2 of the library was encrypting individual elements in a very inefficient manner. Version 3+ only encrypts vectors of values. Your code will have to adapt in order to use it, feel free to take a look at the examples in the repo.