Huelse / SEAL-Python

Microsoft SEAL 4.X For Python
MIT License
321 stars 65 forks source link

How to get the coefficient of ciphertext? #121

Open Cmiiii opened 2 months ago

Cmiiii commented 2 months ago

I tried using the original SEAL library, which defines a data() function in the Ciphertext class that returns the coefficients of the ciphertext. However, I saw in "wrapper.cpp" that SEAL-Python does not seem to include this function.

// ciphertext.h
    py::class_<Ciphertext>(m, "Ciphertext")
        .def(py::init<>())
        .def(py::init<const SEALContext &>())
        .def(py::init<const SEALContext &, parms_id_type>())
        .def(py::init<const SEALContext &, parms_id_type, std::size_t>())
        .def(py::init<const Ciphertext &>())
        .def("coeff_modulus_size", &Ciphertext::coeff_modulus_size)
        .def("poly_modulus_degree", &Ciphertext::poly_modulus_degree)
        .def("size", &Ciphertext::size)
        .def("size_capacity", &Ciphertext::size_capacity)
        .def("is_transparent", &Ciphertext::is_transparent)
        .def("is_ntt_form", py::overload_cast<>(&Ciphertext::is_ntt_form, py::const_))
        .def("parms_id", py::overload_cast<>(&Ciphertext::parms_id, py::const_))
        .def("scale", py::overload_cast<>(&Ciphertext::scale, py::const_))
        .def("scale", [](Ciphertext &cipher, double scale){
            cipher.scale() = scale;
        })
        .def("save", [](const Ciphertext &cipher, const std::string &path){
            std::ofstream out(path, std::ios::binary);
            cipher.save(out);
            out.close();
        })
        .def("load", [](Ciphertext &cipher, const SEALContext &context, const std::string &path){
            std::ifstream in(path, std::ios::binary);
            cipher.load(context, in);
            in.close();
        })
        .def("save_size", [](const Ciphertext &cipher){
            return cipher.save_size();
        })
        .def("to_string", [](const Ciphertext &cipher){
            std::stringstream out(std::ios::binary | std::ios::out);
            cipher.save(out);
            return py::bytes(out.str());
        });
Huelse commented 2 months ago

Sorry for replying late, the data() function returns a pointer to the beginning of the ciphertext data, which we think might not be safe, so you can write a lambda function like "to_string" to get the data you want.

Cmiiii commented 2 months ago

Sorry for replying late, the data() function returns a pointer to the beginning of the ciphertext data, which we think might not be safe, so you can write a lambda function like "to_string" to get the data you want.

Thank you for your reply! I saw the relevant ciphertext storage method in the 7_serialization.py file. But there is one question that puzzles me. When my ciphertext modulus is set to [60,40,40,60] and the polynomial order is set to 16384, and referring to the original SEAL code, it defines the coefficient type as uint64_t. If I am not mistaken, the ciphertext coefficients have a total of 64 bits163844/8=524288 bytes. But when I use the os.path.getsize() function to get the size of the 'cipher,bin' file, the data I get does not match it, so I would like to ask if the 'cipher.bin' file only contains the ciphertext coefficient data?

Huelse commented 2 months ago

Not, the to_string method will serialize the data and it has the SEAL header, params, and data.

Cmiiii commented 2 months ago

Not, the to_string method will serialize the data and it has the SEAL header, params, and data.

Then I still can't get the coefficients of the ciphertext. In the original SEAL library, the variable 'data_' that stores the ciphertext coefficients is a private variable of the 'Ciphertext' class. The 'data()' function returns a pointer, which is not supported by Python. So what should I do?

Huelse commented 2 months ago

write a function like this:

.def("get_coeffs", [](const Ciphertext &cipher){
    auto data = cipher.data();
   // handle the data
   // return the coeff list py:list or py::array_t
})