Proxy Re-encryption (PRE) using CKKS Homomorphic Encryption
We live in a legal world of proxies. When you purchase a house, you will use a trusted solicitor to act on your behalf. So, if Alice is selling a house to Bob, then Trent needs to have trusted access to Alice’s funds. We will then check things with the transaction and pass the funds on to Bob. So, with encryption, can we perform the same operation, where we take a crypto asset and pass its ownership from Alice to Bob, and use a trusted proxy? For this, we can use Proxy Re-encryption (PRE).
With public key encryption, we can encrypt with a public key and then decrypt with a private key. And, so, if we have some ciphertext, and we want to pass this on to Bob, we would have to re-encrypt by decrypting with Alice’s private key, and then re-encrypt with Bob’s public key. With proxy re-encryption (PRE), we can convert ciphertext encrypted with Alice’s public key into one that Bob can decrypt with his private key.
In this case, we might have a trusted proxy agent, such as Trent, and who is trusted to use Alice’s private key. Trent can either be trusted to hold Alice’s private key, or Alice can use her private key and Bob’s public key to create the re-encryption key.
To encrypt data with Alice’s public key and then decrypt with her private key:
auto plaintext = cc->MakeCKKSPackedPlaintext(dataInput);
auto ciphertext1 = cc->Encrypt(aliceKey.publicKey, plaintext);
Plaintext plaintextDec1;
cc->Decrypt(aliceKey.secretKey, ciphertext1, &plaintextDec1);
We can use Bob’s public key and Alice’s private key to create a re-generation key, after which we can decrypt with Bob’s private key:
Plaintext plaintextDec;
auto bobKey = cc->KeyGen();
auto reencryptionKey = cc->ReKeyGen(aliceKey.secretKey, bobKey.publicKey);
auto reEncryptedCT = cc->ReEncrypt(ciphertext1, reencryptionKey);
cc->Decrypt(bobKey.secretKey, reEncryptedCT, &plaintextDec);
The full coding 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.9";
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="10.1 20.5 30.1 1.2";
CCParams<CryptoContextCKKSRNS> parameters;
std::vector<double> dataInput = split(s1);
parameters.SetBatchSize(16);
parameters.SetMultiplicativeDepth(2);
parameters.SetScalingModSize(59);
parameters.SetSecurityLevel(SecurityLevel::HEStd_128_classic);
parameters.SetRingDim(16384);
parameters.SetPREMode(INDCPA);
parameters.SetKeySwitchTechnique(KeySwitchTechnique::HYBRID);
auto cc = GenCryptoContext(parameters);
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
cc->Enable(PRE);
auto aliceKey = cc->KeyGen();
auto plaintext = cc->MakeCKKSPackedPlaintext(dataInput);
plaintext->SetLength(s1.size());
auto ciphertext1 = cc->Encrypt(aliceKey.publicKey, plaintext);
Plaintext plaintextDec1;
cc->Decrypt(aliceKey.secretKey, ciphertext1, &plaintextDec1);
Plaintext plaintextDec;
auto bobKey = cc->KeyGen();
auto reencryptionKey = cc->ReKeyGen(aliceKey.secretKey, bobKey.publicKey);
auto reEncryptedCT = cc->ReEncrypt(ciphertext1, reencryptionKey);
cc->Decrypt(bobKey.secretKey, reEncryptedCT, &plaintextDec);
plaintextDec1->SetLength(dataInput.size());
plaintextDec->SetLength(dataInput.size());
cout << "Decrypted data before proxy encryption: " << plaintextDec1 << endl;
cout<< "Decrypted data after proxy encryption: " << plaintextDec << endl;
return 0;
}
A sample run is [here]:
Decrypted data before proxy encryption: (0.5, 0.7, 0.9, ... ); Estimated precision: 52 bits
Decrypted data after proxy encryption: (0.5, 0.7, 0.9, ... ); Estimated precision: 52 bits
Conclusions
We have conducted the PRE using the CKKS homomorphic encryption method. If you want to find out more about homomorphic encryption, try here:
and: