Logistic Function In Homomorphic Encryption — A Base for Privacy-Aware Machine Learning

Prof Bill Buchanan OBE FRSE
4 min readAug 5, 2024

We live in a world where AI can harvest citizen data. But can we find a way that we can learn on encrypted data? Well, with homomorphic encryption we can use encrypted data for our processing. So:

Enc(a operator b) = Enc(a) operator Enc(b)

and where operator could be any mathematical operation. While LLMs are a kinda false type of learning, the usage of artificial neural networks (ANN) allows us the opportunity to learn from data in the same way that our brain works. At the core of this is the logistic function (also known as the sigmoid function):

Ref: [Wikipedia]

Mathematically, this is defined as:

For example, if we have x=0.5, then, in Python, we get:

>>> import math
>>> x=0.5
>>> y=1/(1+math.exp(-x))
>>> print (y)
0.6224593312018546
>>> x=6
>>> print (y)
0.9975273768433653

An artificial neural network is created with weighted summation and a sigmoid function:

Approximate logistic function with Chebyshev approximation

With homomorphic encryption we can represent a mathematical operation in the form for a homomorphic equation. One of the most widely used methods is to use Chebyshev polynomials, and which allows the mapping of the function to a Chebyshev approximation. This is supported in OpenFHE, and which implements Chebyshev approximation. For this, we can use the function of:

Ciphertext<Element> EvalLogistic(ConstCiphertext<Element> ciphertext, double a, double b, uint32_t degree) const

and which evaluates 1/(1 + exp(-x)) for f(x), and where x is a range of coefficients with ciphertext. The value of a is the lower bound of the coefficients, and b is the upport bound. The degree value is the desired degree of approximation.

The code to implement is [here]:


#include <openfhe.h>

using namespace lbcrypto;
using namespace std;

#include <iostream>
#include <sstream>
#include <cstdint>


std::string ReadAndRemoveFirstTokenFromString (const char &separator, std::string& line) // faster than stringstream, at least for reading first element
{
auto found=line.find(separator);
if (found==std::string::npos)
{ string hold=line;
line.clear();
return hold;
}
else
{
std::string out=line.substr(0,found);
line=line.substr(found+1,line.size());
while (line[0]==' ') line=line.substr(1,line.size());
if (out=="") out="-999999.0";
return out;
}
}
vector<double> split(string a)
{

std::vector <double> number;
while(a.size()>0)
{
string num=ReadAndRemoveFirstTokenFromString(' ', a);
if ((num=="\0") || (num.empty())) number.emplace_back(-999999.0);
else number.emplace_back(stod(num));
}
return number;
}

int main(int argc, char *argv[]) {


string s1="0.5 0.7 0.9";

if (argc>1) {
s1= (argv[1]);

}

auto input= split(s1);


std::cout << "Logistic Evaluation \n" << std::endl;

CCParams<CryptoContextCKKSRNS> parameters;
parameters.SetMultiplicativeDepth(5);
parameters.SetScalingModSize(40);

CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
cc->Enable(ADVANCEDSHE);

size_t encodedLength = input.size();


Plaintext plaintext1 = cc->MakeCKKSPackedPlaintext(input);

auto keyPair = cc->KeyGen();

std::cout << "Generating evaluation key.";
cc->EvalMultKeyGen(keyPair.secretKey);


auto ciphertext1 = cc->Encrypt(keyPair.publicKey, plaintext1);


auto result = cc->EvalLogistic(ciphertext1,-1,1,3);

Plaintext plaintextDec;

cc->Decrypt(keyPair.secretKey, result, &plaintextDec);

plaintextDec->SetLength(encodedLength);


std::cout << "Input values: " << plaintext1 << std::endl;

std::cout << "Results: :" << plaintextDec << std::endl;



return 0;

}

and a sample run [here]:

Logistic Evaluation 

Generating evaluation key.Input values: (0.5, 0.7, 0.9, ... ); Estimated precision: 40 bits

Results: :(0.622517, 0.668345, 0.710995, ... ); Estimated precision: 27 bits

In this case we have:

Conclusions

We need to find better ways of training machines, and protect data. Homomorphic encryption gives us one way of doing this, and the logistic function is at the core of this. You will find more examples here:

and:

--

--

Prof Bill Buchanan OBE FRSE

Professor of Cryptography. Serial innovator. Believer in fairness, justice & freedom. Based in Edinburgh. Old World Breaker. New World Creator. Building trust.