SEAL icon indicating copy to clipboard operation
SEAL copied to clipboard

Euclidean Distance

Open AlaaMSI opened this issue 3 years ago • 2 comments

Hello,

I am writing a code to calculate the Euclidean distance between two vectors, where both of them are encrypted. and I have yet to master SEAL, so I have some questions.

  1. what I did so far is the subtraction and the squaring, however, for the summation I am using evaluator.add_many which is supposed to accept a vector as a first argument and a destination on the second. the squaring result is declared as a Ciphertext, I get "cannot convert argument 1 from Ciphertext to vector", then when I try to declare it as a vector the evaluator.square doesn't work because of the expected input datatypes. How can I use add_many? .... I tried to convert all of the ciphertexts to vector<Ciphertext> but it caused an error to the header file.

  2. The square root was mentioned in a talk that it could be approximated. would using the power function suffices?

I am attaching the code in hopes that it would shed the light on what's wrong


void testDistance() {

    EncryptionParameters parms(scheme_type::bfv);;
    size_t poly_modulus_degree = 8192;
    parms.set_poly_modulus_degree(poly_modulus_degree);
    parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
    parms.set_plain_modulus(PlainModulus::Batching(poly_modulus_degree, 50));

    SEALContext context(parms);
    
    print_parameters(context);
    cout << endl;

    auto qualifiers = context.first_context_data()->qualifiers();
    cout << "Batching enabled: " << boolalpha << qualifiers.using_batching << endl;

    KeyGenerator keygen(context);
    SecretKey secret_key = keygen.secret_key();
    PublicKey public_key;
    keygen.create_public_key(public_key);
    Encryptor encryptor(context, public_key);
    Evaluator evaluator(context);
    Decryptor decryptor(context, secret_key);
    
    BatchEncoder batch_encoder(context);
  
    size_t slot_count = batch_encoder.slot_count();
    size_t row_size = slot_count / 2;
    cout << "Plaintext vector row size: " << row_size << endl;
    
    
    vector<int64_t> x_vector(slot_count, 0ULL);

    x_vector[0] = 1;
    x_vector[1] = 2;
    x_vector[2] = 3;
    x_vector[3] = 4;
    x_vector[4] = 5;
    x_vector[5] = 6;
    x_vector[6] = 7;

   
    cout << "x plaintext vector: " << endl;
    print_matrix(x_vector, row_size);

    Plaintext x_plain_vector;
    print_line(__LINE__);
    cout << "Encode plaintext x vector: " << endl;
    batch_encoder.encode(x_vector, x_plain_vector);

    Ciphertext x_encrypted_vector;
    cout << "Encrypt plain_vector x to encrypted_vector." << endl;
    Stopwatch sw("Encryption Time");
	encryptor.encrypt(x_plain_vector, x_encrypted_vector);
        cout << "    + Noise budget in encrypted_matrix: " << decryptor.invariant_noise_budget(x_encrypted_vector) << " bits"
            << endl;
 
   
    

    vector<int64_t> y_vector(slot_count, 0ULL);
    y_vector[0] = 7;
    y_vector[1] = 6;
    y_vector[2] = 5;
    y_vector[3] = 4;
    y_vector[4] = 3;
    y_vector[5] = 2;
    y_vector[6] = 1;

    
    cout << "y plaintext vector:" << endl;
    print_matrix(y_vector, row_size);

    Plaintext y_plain_vector;
    cout << "Encode plaintext y vector:" << endl;
    batch_encoder.encode(y_vector, y_plain_vector);

    Ciphertext y_encrypted_vector;
	Ciphertext squared;
    Ciphertext subtracted;
	
	encryptor.encrypt(y_plain_vector, y_encrypted_vector);
        cout << "    + Noise budget in encrypted_matrix: " << decryptor.invariant_noise_budget(y_encrypted_vector) << " bits"
            << endl;
    cout << "Encrypt plain_vector y to encrypted_vector." << endl;
    
	evaluator.sub(x_encrypted_vector, y_encrypted_vector, subtracted);
	evaluator.square(subtracted, squared);
   
    Ciphertext addition;
    /* Here I am supposed to use add_many for addition*/
        
    //evaluator.add_many(squared, addition);
 

      // Decrypt the result
    Plaintext x_plain_result;
    decryptor.decrypt(addition, x_plain_result);
    

    vector <uint64_t> pod_result;
    cout << "    + Decode plaintext matrix ...... Correct." << endl;
    batch_encoder.decode(x_plain_result, pod_result);
   

    for (int i = 0; i < 7; i++) {

        cout << pod_result[i] << endl;

    }
    
}

Thank you in advance.

AlaaMSI avatar Oct 31 '22 13:10 AlaaMSI

Don't use add_many if you have a single Ciphertext then.

would using the power function suffices?

What do you mean by the power function?

WeiDaiWD avatar Nov 15 '22 19:11 WeiDaiWD

Thank you Mr. @WeiDaiWD for taking the time to answer my question, I understand I am asking questions coming from inexperience.

Don't use add_many if you have a single Ciphertext then.

I used rotate rows and and then I added it to the first cell of a copied squared ciphertext. I kept rotating and adding.

What do you mean by the power function?

As for the power function, I keep thinking of alternative ways to approximately calculate a root but I am not sure what would work in an encrypted domain, what I meant by power function is to use the power to scale down a ciphertext's plaintext value. Or maybe multiplying it with a constant that could result in a number close to the expected. However, I am not sure how to do the approximation as these two vectors should represent image features and I am not confident that the result won't be too tailored for some and doesn't work on others.

AlaaMSI avatar Nov 20 '22 12:11 AlaaMSI