Search code examples
sealhomomorphism

How would I go about retrieving the binary representation of a ciphertext as it would be stored to disk


This question is in reference to version 3.0 of the Microsoft Simple Encrypted Arithmetic Library (SEAL), in case it is not evident from the tag.

I'm trying to extract and evaluate the actual bits that will be written to memory, as stored in the Ciphertext class. I'm at a loss for how to do so; the internal representation appears to include 65 bytes of additional information, and it is not clear how much of this is necessary to reconstruct the ciphertext when it is read back. Is there any other part of the save function that will be necessary to reconstruct the ciphertext, assuming the system parameters are fixed and known a priori?

After combing over the code, I decided to try preparing a Ciphertext with my encoder, retrieving the uint64_count, and then iterating over the coefficients using the [] operator overload. If these values are zero-padded to some common length, would this be a faithful representation of the underlying data?

Thanks in advance


Solution

  • The Ciphertext class contains the following member variables:

    parms_id_type parms_id_ = parms_id_zero;
    bool is_ntt_form_ = false;
    size_type size_capacity_ = 2;
    size_type size_ = 0;
    size_type poly_modulus_degree_ = 0;
    size_type coeff_mod_count_ = 0;
    double scale_ = 1.0;
    IntArray<ct_coeff_type> data_;
    

    If you know the parameters (parms_id_, poly_modulus_degree_, coeff_mod_count_) then

    (1) if you use the BFV scheme scale == 1.0 and is_ntt_form_ == false unless you've manually transformed the ciphertext. Finally, size_ == 2 if you have a freshly encrypted ciphertext, and whenever you are (de)serializing ciphertexts it probably will be 2;

    (2) if you use the CKKS scheme you need to know the scale. If this is supposed to be a freshly encrypted ciphertext then perhaps you stick to some convention like using the last coeff_modulus prime as the scale, in which case you would know it from the parameters. For the CKKS scheme the is_ntt_form_ == true unless you've manually transformed the ciphertext. Again, most likely size_ == 2 in your use-case.

    Given this, you have all of the information to populate the different fields. All you need to do is read the data from data_ using IntArray<ct_coeff_type>::save/load. There is some small overhead there too, as it saves also the total word count in addition to the data.

    I'm not sure what you mean by zero-padding. Note that the values you get with operator[] are not really the polynomial coefficients but instead parts of a CRT representation of the ciphertext data (see this SO question. Since these numbers are integers modulo some up to 60-bit prime, there will be some zeros there in the high-order bits that can be safely compressed away for storage and restored for computation.