Skip to content

Possible inconsistent size reported for Plaintext in save_size #66

@s0l0ist

Description

@s0l0ist

When serializing/deserializing Plaintexts, there was an inconsistent size estimation resulting from an improper type when computing ComprSizeEstimate.

Previously, when running the following code:

plaintext.h line ~572:

SEAL_NODISCARD inline std::streamoff save_size(
            compr_mode_type compr_mode) const
        {
            std::size_t members_size = Serialization::ComprSizeEstimate(
                util::add_safe(
                    sizeof(parms_id_),
                    sizeof(coeff_count_), // <--------------------- Offending member
                    sizeof(scale_),
                    util::safe_cast<std::size_t>(
                        data_.save_size(compr_mode_type::none))),
                compr_mode);
            std::cout << "Plaintext::save_size member_size (" << members_size << ")" <<std::endl;

            auto size = util::safe_cast<std::streamoff>(util::add_safe(
                    sizeof(Serialization::SEALHeader),
                    members_size
                ));
            std::cout << "Plaintext::save_size size (" << size << ")" <<std::endl;

            return size;
//            return util::safe_cast<std::streamoff>(util::add_safe(
//                sizeof(Serialization::SEALHeader),
//                members_size
//            ));
        }

Results in the incorrect member_size:

Plaintext::save_size member_size (32836)
Plaintext::save_size size (32852)

This, in turn, becomes an issue when deserializing a saved Plaintext stream where the stream.tellg() position calculation throws here:

serialization.cpp line ~657:

if (header.size != stream.tellg() - stream_start_pos)

Replacing it with the following:

SEAL_NODISCARD inline std::streamoff save_size(
            compr_mode_type compr_mode) const
        {
            std::size_t members_size = Serialization::ComprSizeEstimate(
                util::add_safe(
                    sizeof(parms_id_),
                    sizeof(uint64_t), // coeff_count_ <--------------------- Modified member
                    sizeof(scale_),
                    util::safe_cast<std::size_t>(
                        data_.save_size(compr_mode_type::none))),
                compr_mode);
            std::cout << "Plaintext::save_size member_size (" << members_size << ")" <<std::endl;

            auto size = util::safe_cast<std::streamoff>(util::add_safe(
                    sizeof(Serialization::SEALHeader),
                    members_size
                ));
            std::cout << "Plaintext::save_size size (" << size << ")" <<std::endl;

            return size;
//            return util::safe_cast<std::streamoff>(util::add_safe(
//                sizeof(Serialization::SEALHeader),
//                members_size
//            ));

Results in the correct member_size:

Plaintext::save_size member_size (32840)
Plaintext::save_size size (32856)

This change in Plaintext.h resembles the uint64_t setting for coeff_mod_count_ in Ciphertext.cpp.

Parameters to reproduce (pseudo code):

EncParms: {
    schemeType: BFV,
    polyModulusDegree: 4096,
    security: tc128,
    plainModulus: Batching(polyModulusDegree: 4096, bitsize: 20)
    coeffModulus: BFVDefault(polyModulusDegree: 4096,
          security: tc128)
}

Context: {
    expandModChain: true,
    security: tc128
}

Create a Plaintext and encode 4096 (max size of polyModulusDegree) misc values to it (within range)

Save the plaintext to a stream. (where the header size is computed incorrectly)

Attempt to load from the same stream. (where it throws during runtime)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions