Commit 9c75e46c authored by Gerard Ryan's avatar Gerard Ryan
Browse files

Merge branch 'polyakov-bfvrns-v2' into 'v1.1.1-work-branch'

Polyakov bfvrns v2

Equivalent of https://git.njit.edu/palisade/palisade-student-edition/merge_requests/363 but for the v1.1.1 branch. The polyakov-bfvrns-v2 branch can be deleted when this merge request is processed (it's been merged to master).

See merge request !364
parents 5a1c50a4 6a2c5afc
......@@ -1000,7 +1000,7 @@ NativePoly DCRTPolyImpl<ModType,IntType,VecType,ParmType>::DecryptionCRTInterpol
return this->CRTInterpolate().DecryptionCRTInterpolate(ptm);
}
//Source: Halevi S., Polyakov Y., Shoup V. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
//Source: Halevi S. and Polyakov Y. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
//
//Computes Round(p/q*x) mod p as [\sum_i x_i*alpha_i + Round(\sum_i x_i*beta_i)] mod p for fast rounding in RNS
// vectors alpha and beta are precomputed as
......@@ -1044,7 +1044,7 @@ DCRTPolyImpl<ModType,IntType,VecType,ParmType>::ScaleAndRound(const typename Pol
}
/*
* Source: Halevi S., Polyakov Y., Shoup V. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
* Source: Halevi S. and Polyakov Y. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
*
* The goal is to switch the basis of x from Q to S
*
......@@ -1082,33 +1082,59 @@ DCRTPolyImpl<ModType,IntType,VecType,ParmType> DCRTPolyImpl<ModType,IntType,VecT
for( usint rIndex = 0; rIndex < ringDimension; rIndex++ ) {
std::vector<typename PolyType::Integer> xInvVector(nTowers);
double lyam = 0.0;
// Compute alpha and vector of x_i terms
for( usint vIndex = 0; vIndex < nTowers; vIndex++ ) {
const typename PolyType::Integer &xi = m_vectors[vIndex].GetValues()[rIndex];
const typename PolyType::Integer &qi = m_vectors[vIndex].GetModulus();
//computes [xi (q/qi)^{-1}]_qi
xInvVector[vIndex] = xi.ModMulFast(qInvModqi[vIndex],qi);
//computes [xi (q/qi)^{-1}]_qi / qi to keep track of the number of q-overflows
lyam += (double)xInvVector[vIndex].ConvertToInt()/(double)qi.ConvertToInt();
}
// alpha corresponds to the number of overflows
typename PolyType::Integer alpha = std::llround(lyam);
// alpha may get estimated incorrectly in this region; so we apply a correction procedure
// currently we use the multiprecision approach for simplicity but we will change it to
// the single-precision approach proposed by Kawamura et al. in https://doi.org/10.1007/3-540-45539-6_37
if ((std::fabs(std::llround(lyam*2)/(double)2 - lyam) < nTowers*(2.22e-16)) && (std::llround(lyam*2) % 2 == 1) ){
BigInteger xBig = 0;
for( usint vIndex = 0; vIndex < nTowers; vIndex++ ) {
BigInteger qi = m_vectors[vIndex].GetModulus();
xBig += xInvVector[vIndex]*params->GetModulus()/qi;
}
BigInteger alphaBig = xBig.DivideAndRound(params->GetModulus());
alpha = alphaBig.ConvertToInt();
}
for (usint newvIndex = 0; newvIndex < nTowersNew; newvIndex ++ ) {
double lyam = 0.0;
typename PolyType::Integer curValue = 0;
const typename PolyType::Integer &si = ans.m_vectors[newvIndex].GetModulus();
//first round - compute "fast conversion"
for( usint vIndex = 0; vIndex < nTowers; vIndex++ ) {
const typename PolyType::Integer &xi = m_vectors[vIndex].GetValues()[rIndex];
const typename PolyType::Integer &qi = m_vectors[vIndex].GetModulus();
//computes [xi (q/qi)^{-1}]_qi
const typename PolyType::Integer &xInv = xi.ModMulFast(qInvModqi[vIndex],qi);
//computes [xi (q/qi)^{-1}]_qi / qi to keep track of the number of q-overflows
lyam += (double)xInv.ConvertToInt()/(double)qi.ConvertToInt();
curValue += xInv.ModMulFast(qDivqiModsi[newvIndex][vIndex],si);
curValue += xInvVector[vIndex].ModMulFast(qDivqiModsi[newvIndex][vIndex],si);
}
// Since we let current value to exceed si to avoid extra modulo reductions, we have to apply mod si now
curValue = curValue.Mod(si);
// alpha corresponds to the number of overflows
typename PolyType::Integer alpha = std::llround(lyam);
//second round - remove q-overflows
ans.m_vectors[newvIndex].at(rIndex) = curValue.ModSubFast(alpha.ModMulFast(qModsi[newvIndex],si),si);
......@@ -1120,7 +1146,7 @@ DCRTPolyImpl<ModType,IntType,VecType,ParmType> DCRTPolyImpl<ModType,IntType,VecT
}
// Source: Halevi S., Polyakov Y., Shoup V. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
// Source: Halevi S. and Polyakov Y. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
//
// @brief Expands polynomial in CRT basis Q = q1*q2*...*qn to a larger CRT basis Q*S, where S = s1*s2*...*sn;
// uses SwichCRTBasis as a subroutine; Outputs the resulting polynomial in EVALUATION representation
......@@ -1168,7 +1194,7 @@ void DCRTPolyImpl<ModType,IntType,VecType,ParmType>::ExpandCRTBasis(const shared
}
//Source: Halevi S., Polyakov Y., Shoup V. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
//Source: Halevi S. and Polyakov Y. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
//
// Computes Round(p/Q*x), where x is in the CRT basis Q*S,
// as [\sum_{i=1}^n alpha_i*x_i + Round(\sum_{i=1}^n beta_i*x_i)]_si,
......
......@@ -48,7 +48,7 @@ namespace lbcrypto {
//Macros for convenient definitions of class implementations of special functions
//Matrix<T>& Matrix<T>::Ones()
//Matrix<T>& Matrix<T>::Ones()
#define ONES_FOR_TYPE(T) \
template<> \
Matrix<T>& Matrix<T>::Ones() { \
......@@ -66,7 +66,7 @@ namespace lbcrypto {
ONES_FOR_TYPE(NativePoly)
ONES_FOR_TYPE(BigInteger)
ONES_FOR_TYPE(BigVector)
ONES_FOR_TYPE(Field2n)
//template<>
......@@ -103,10 +103,10 @@ namespace lbcrypto {
IDENTITY_FOR_TYPE(BigVector)
IDENTITY_FOR_TYPE(Field2n)
//Matrix<T> Matrix<T>::GadgetVector(int32_t base)
//Matrix<T> Matrix<T>::GadgetVector(int64_t base)
#define GADGET_FOR_TYPE(T) \
template<> \
Matrix<T> Matrix<T>::GadgetVector(int32_t base) const { \
Matrix<T> Matrix<T>::GadgetVector(int64_t base) const { \
Matrix<T> g(allocZero, rows, cols); \
auto base_matrix = allocZero(); \
*base_matrix = base; \
......@@ -118,6 +118,7 @@ namespace lbcrypto {
}
GADGET_FOR_TYPE(int32_t)
GADGET_FOR_TYPE(int64_t)
GADGET_FOR_TYPE(double)
GADGET_FOR_TYPE(Poly)
GADGET_FOR_TYPE(NativePoly)
......@@ -201,6 +202,26 @@ namespace lbcrypto {
SPLIT32ALT_FOR_TYPE(NativePoly)
SPLIT32ALT_FOR_TYPE(DCRTPoly)
// split a vector of BigInteger into a vector of ring elements with ring dimension n
#define SPLIT64ALT_FOR_TYPE(T) \
template<> \
Matrix<T> SplitInt64AltIntoElements(Matrix<int64_t> const& other, size_t n, const shared_ptr<typename T::Params> params) { \
auto zero_alloc = T::MakeAllocator(params, COEFFICIENT); \
size_t rows = other.GetRows(); \
Matrix<T> result(zero_alloc, rows, 1); \
for (size_t row = 0; row < rows; ++row) { \
std::vector<int64_t> values(n); \
for (size_t i = 0; i < n; ++i) \
values[i] = other(row, i); \
result(row, 0) = values; \
} \
return result; \
}
SPLIT64ALT_FOR_TYPE(Poly)
SPLIT64ALT_FOR_TYPE(NativePoly)
SPLIT64ALT_FOR_TYPE(DCRTPoly)
template<>
void Matrix<Poly>::SetFormat(Format format) {
for (size_t row = 0; row < rows; ++row) {
......
......@@ -158,7 +158,7 @@ public:
* @param base is the base the digits of the matrix are represented in
* @return the resulting matrix
*/
Matrix<Element> GadgetVector(int32_t base = 2) const;
Matrix<Element> GadgetVector(int64_t base = 2) const;
/**
* Computes the infinity norm
......@@ -631,5 +631,16 @@ Matrix<Element> SplitInt64IntoElements(Matrix<int64_t> const& other, size_t n, c
*/
template<typename Element>
Matrix<Element> SplitInt32AltIntoElements(Matrix<int32_t> const& other, size_t n, const shared_ptr<typename Element::Params> params);
/**
* Split a vector of int64_t into a vector of ring elements with ring dimension n
*
* @param &other the input matrix
* @param &n the ring dimension
* @param &params Poly element params
* @return the resulting matrix of Poly
*/
template<typename Element>
Matrix<Element> SplitInt64AltIntoElements(Matrix<int64_t> const& other, size_t n, const shared_ptr<typename Element::Params> params);
}
#endif // LBCRYPTO_MATH_MATRIX_H
......@@ -29,7 +29,7 @@ BFV RNS testing programs
#include <iostream>
#include <fstream>
#include <limits>
#include "palisade.h"
......@@ -43,6 +43,7 @@ BFV RNS testing programs
#include "math/nbtheory.h"
typedef std::numeric_limits< double > dbl;
using namespace std;
using namespace lbcrypto;
......@@ -56,17 +57,19 @@ void SHETestCoeff();
void SHETestPacked();
void SHETestPackedInnerProduct();
void SwitchCRT();
void SwitchCRTSingleTests();
void Multiply();
void MultiplyTwo();
void MultiplyThree();
int main() {
PKE();
SHETestCoeff();
SHETestPacked();
SHETestPackedInnerProduct();
//PKE();
//SHETestCoeff();
//SHETestPacked();
//SHETestPackedInnerProduct();
//SwitchCRT();
SwitchCRTSingleTests();
//Multiply();
//MultiplyTwo();
//MultiplyThree();
......@@ -321,7 +324,7 @@ void SHETestPacked() {
//Set Crypto Parameters
CryptoContext<DCRTPoly> cryptoContext = CryptoContextFactory<DCRTPoly>::genCryptoContextBFVrns(
ptm, rootHermiteFactor, sigma, 0, 6, 0, OPTIMIZED,7);
ptm, rootHermiteFactor, sigma, 0, 11, 0, OPTIMIZED,7);
// enable features that you wish to use
cryptoContext->Enable(ENCRYPTION);
......@@ -686,6 +689,100 @@ void SwitchCRT() {
}
void SwitchCRTSingleTests() {
std::cout << "\n===========TESTING CRT SWITCH===============: " << std::endl;
std::cout << "\nThis code demonstrates the use of the BFV-RNS scheme for basic homomorphic encryption operations. " << std::endl;
std::cout << "This code shows how to auto-generate parameters during run-time based on desired plaintext moduli and security levels. " << std::endl;
std::cout << "In this demonstration we use three input plaintext and show how to both add them together and multiply them together. " << std::endl;
//Generate parameters.
//double diff, start, finish;
usint ptm = 1<<31;
double sigma = 3.2;
double rootHermiteFactor = 1.006;
//Set Crypto Parameters
CryptoContext<DCRTPoly> cryptoContext = CryptoContextFactory<DCRTPoly>::genCryptoContextBFVrns(
ptm, rootHermiteFactor, sigma, 0, 7, 0, OPTIMIZED,8);
std::cout << "p = " << cryptoContext->GetCryptoParameters()->GetPlaintextModulus() << std::endl;
std::cout << "n = " << cryptoContext->GetCryptoParameters()->GetElementParams()->GetCyclotomicOrder() / 2 << std::endl;
std::cout << "log2 q = " << log2(cryptoContext->GetCryptoParameters()->GetElementParams()->GetModulus().ConvertToDouble()) << std::endl;
const shared_ptr<ILDCRTParams<BigInteger>> params = cryptoContext->GetCryptoParameters()->GetElementParams();
const shared_ptr<LPCryptoParametersBFVrns<DCRTPoly>> cryptoParamsBFVrns = std::dynamic_pointer_cast<LPCryptoParametersBFVrns<DCRTPoly>>(cryptoContext->GetCryptoParameters());
const shared_ptr<ILDCRTParams<BigInteger>> paramsS = cryptoParamsBFVrns->GetDCRTParamsS();
size_t counter = 0;
for(size_t k = 0; k < 3052; k++){
typename DCRTPoly::DugType dug;
const DCRTPoly a(dug, params, Format::COEFFICIENT);
Poly resultA = a.CRTInterpolate();
const DCRTPoly b = a.SwitchCRTBasis(paramsS, cryptoParamsBFVrns->GetCRTInverseTable(),
cryptoParamsBFVrns->GetCRTqDivqiModsiTable(), cryptoParamsBFVrns->GetCRTqModsiTable());
Poly resultB = b.CRTInterpolate();
for (size_t i = 0; i < resultA.GetLength(); i++)
{
counter++;
BigInteger halfa = resultA.GetModulus()>>1;
BigInteger halfb = resultB.GetModulus()>>1;
BigInteger aInt, bInt;
if (resultA[i]>halfa)
aInt = resultA.GetModulus() - resultA[i];
else
aInt = resultA[i];
if (resultB[i]>halfb)
bInt = resultB.GetModulus() - resultB[i];
else
bInt = resultB[i];
if (aInt != bInt) {
double lyam = 0.0;
size_t nTowers = a.GetNumOfElements();
// Compute alpha and vector of x_i terms
for( usint vIndex = 0; vIndex < nTowers; vIndex++ ) {
const NativeInteger &xi = a.GetElementAtIndex(vIndex).GetValues()[i];
const NativeInteger &qi = a.GetElementAtIndex(vIndex).GetModulus();
//computes [xi (q/qi)^{-1}]_qi
NativeInteger xInv = xi.ModMulFast( cryptoParamsBFVrns->GetCRTInverseTable()[vIndex],qi);
//computes [xi (q/qi)^{-1}]_qi / qi to keep track of the number of q-overflows
lyam += (double)xInv.ConvertToInt()/(double)qi.ConvertToInt();
}
cout.precision(dbl::max_digits10);
cout << "counter \t" << counter <<"; lyam: \t" << fixed << lyam << endl;
}
}
//std::cout << "counter \t" << counter << std::endl;
}
}
void Multiply() {
std::cout << "\n===========TESTING POLYNOMIAL MULTIPLICATION - ONE TERM IS CONSTANT POLYNOMIAL===============: " << std::endl;
......
......@@ -33,6 +33,7 @@ The BFV scheme is introduced in the following papers:
- Junfeng Fan and Frederik Vercauteren (2012). Somewhat Practical Fully Homomorphic Encryption. Cryptology ePrint Archive, Report 2012/144. (https://eprint.iacr.org/2012/144.pdf)
Our implementation builds from the designs here:
- Halevi S. and Polyakov Y. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
- Lepoint T., Naehrig M. (2014) A Comparison of the Homomorphic Encryption Schemes FV and YASHE. In: Pointcheval D., Vergnaud D. (eds) Progress in Cryptology – AFRICACRYPT 2014. AFRICACRYPT 2014. Lecture Notes in Computer Science, vol 8469. Springer, Cham. (https://eprint.iacr.org/2014/062.pdf)
- Jean-Claude Bajard and Julien Eynard and Anwar Hasan and Vincent Zucca (2016). A Full RNS Variant of FV like Somewhat Homomorphic Encryption Schemes. Cryptology ePrint Archive, Report 2016/510. (https://eprint.iacr.org/2016/510)
......
......@@ -32,7 +32,7 @@
* - Junfeng Fan and Frederik Vercauteren (2012). Somewhat Practical Fully Homomorphic Encryption. Cryptology ePrint Archive, Report 2012/144. (https://eprint.iacr.org/2012/144.pdf)
*
* Our implementation builds from the designs here:
* - Halevi S., Polyakov Y., Shoup V. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
* - Halevi S. and Polyakov Y. (in preparation, 2018) A Simpler, Faster RNS Variant of the BFV Homomorphic Encryption Scheme.
* - Lepoint T., Naehrig M. (2014) A Comparison of the Homomorphic Encryption Schemes FV and YASHE. In: Pointcheval D., Vergnaud D. (eds) Progress in Cryptology – AFRICACRYPT 2014. AFRICACRYPT 2014. Lecture Notes in Computer Science, vol 8469. Springer, Cham. (https://eprint.iacr.org/2014/062.pdf)
* - Jean-Claude Bajard and Julien Eynard and Anwar Hasan and Vincent Zucca (2016). A Full RNS Variant of FV like Somewhat Homomorphic Encryption Schemes. Cryptology ePrint Archive, Report 2016/510. (https://eprint.iacr.org/2016/510)
*/
......
......@@ -400,7 +400,7 @@ Matrix<RationalCiphertext<Poly>>& Matrix<RationalCiphertext<Poly>>::Identity() {
}
template<>
Matrix<RationalCiphertext<Poly>> Matrix<RationalCiphertext<Poly>>::GadgetVector(int32_t base) const {
Matrix<RationalCiphertext<Poly>> Matrix<RationalCiphertext<Poly>>::GadgetVector(int64_t base) const {
throw std::logic_error("Cannot create gadget matrix of ciphertext");
}
......@@ -415,7 +415,7 @@ Matrix<RationalCiphertext<NativePoly>>& Matrix<RationalCiphertext<NativePoly>>::
}
template<>
Matrix<RationalCiphertext<NativePoly>> Matrix<RationalCiphertext<NativePoly>>::GadgetVector(int32_t base) const {
Matrix<RationalCiphertext<NativePoly>> Matrix<RationalCiphertext<NativePoly>>::GadgetVector(int64_t base) const {
throw std::logic_error("Cannot create gadget matrix of ciphertext");
}
......
......@@ -64,10 +64,14 @@ int main(int argc, char* argv[]) {
TIC(t);
const auto value1 = algorithm.Evaluate( key, input1);
const auto value2 = algorithm.Evaluate(constrainedKey, input1);
const auto value3 = algorithm.Evaluate( key, input2);
processingTime = TOC(t);
std::cout << "Evaluation (unconstrained): 2 * " << processingTime / 2 << "ms" << std::endl;
TIC(t);
const auto value2 = algorithm.Evaluate(constrainedKey, input1);
const auto value4 = algorithm.Evaluate(constrainedKey, input2);
processingTime = TOC(t);
std::cout << "Evaluation (constrained): 2 * " << processingTime / 2 << "ms" << std::endl;
//std::cout << value1 << std::endl;
//std::cout << value2 << std::endl;
std::cout << "pattern: " << pattern << std::endl;
......@@ -77,5 +81,4 @@ int main(int argc, char* argv[]) {
//std::cout << value4 << std::endl;
std::cout << "input 2: " << input2 << std::endl;
std::cout << (value3 == value4 ? "Matched (Incorrect)" : "Did not match (Correct)") << std::endl;
std::cout << "Evaluation: 4 * " << processingTime / 4 << "ms" << std::endl;
}
......@@ -78,32 +78,32 @@ usint LWEConjunctionCHCPRFAlgorithm<Element>::GetLogModulus() const {
}
template <class Element>
shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> LWEConjunctionCHCPRFAlgorithm<Element>::KeyGen() {
shared_ptr<vector<vector<Element>>> LWEConjunctionCHCPRFAlgorithm<Element>::KeyGen() {
shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> S(new vector<vector<shared_ptr<Matrix<Element>>>>());
shared_ptr<vector<vector<Element>>> s(new vector<vector<Element>>());
for (usint i = 0; i < m_adjustedLength; i++) {
vector<shared_ptr<Matrix<Element>>> S_i;
vector<Element> s_i;
for (usint k = 0; k < m_chunkExponent; k++) {
Element s_ik = Element(m_tug, m_elemParams, COEFFICIENT);
s_ik.SwitchFormat();
shared_ptr<Matrix<Element>> S_ik = Encode(i, i + 1, s_ik);
S_i.push_back(S_ik);
s_i.push_back(s_ik);
}
S->push_back(S_i);
s->push_back(s_i);
}
return S;
return s;
};
template <class Element>
shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> LWEConjunctionCHCPRFAlgorithm<Element>::Constrain(const shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> key, const std::string &pattern) {
shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> LWEConjunctionCHCPRFAlgorithm<Element>::Constrain(const shared_ptr<vector<vector<Element>>> s, const std::string &pattern) {
shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> S(new vector<vector<shared_ptr<Matrix<Element>>>>());
shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> D(new vector<vector<shared_ptr<Matrix<Element>>>>());
for (usint i = 0; i < m_adjustedLength; i++) {
// current chunk of cleartext pattern
......@@ -119,55 +119,57 @@ shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> LWEConjunctionCHCPRFAlgo
chunkTemp = replaceChar(chunk, '?', '0');
usint chunkTarget = std::stoi(chunkTemp, nullptr, 2);
vector<shared_ptr<Matrix<Element>>> S_i;
vector<shared_ptr<Matrix<Element>>> D_i;
for (usint k = 0; k < m_chunkExponent; k++) {
if ((k & chunkMask) == chunkTarget) {
S_i.push_back((*key)[i][k]);
}
else {
// Replace S_ik with fresh encoding if k does not match pattern
Element s_ik = Element(m_tug, m_elemParams, COEFFICIENT);
s_ik.SwitchFormat();
Element s_ik = (*s)[i][k];
shared_ptr<Matrix<Element>> S_ik = Encode(i, i + 1, s_ik);
S_i.push_back(S_ik);
if ((k & chunkMask) != chunkTarget) {
s_ik = Element(m_tug, m_elemParams, COEFFICIENT);
s_ik.SwitchFormat();
}
shared_ptr<Matrix<Element>> D_ik = Encode(i, i + 1, s_ik);
D_i.push_back(D_ik);
}
S->push_back(S_i);
D->push_back(D_i);
}
return S;
return D;
};
template <class Element>
std::string LWEConjunctionCHCPRFAlgorithm<Element>::Evaluate(const shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> key, const std::string &input) const {
std::string LWEConjunctionCHCPRFAlgorithm<Element>::Evaluate(const shared_ptr<vector<vector<Element>>> s, const std::string &input) const {
Matrix<Element> y = (*m_A)[0];
Matrix<Element> y = (*m_A)[m_adjustedLength];
for (usint i = 0; i < m_adjustedLength; i++) {
std::string chunk = input.substr(i * m_chunkSize, m_chunkSize);
int k = std::stoi(chunk, nullptr, 2);
y = y * *(*key)[i][k];
y = y * (*s)[i][k];
}
const BigInteger &q = m_elemParams->GetModulus();
std::stringstream output;
return TransformMatrixToPRFOutput(y);
for (size_t i = 0; i < y.GetCols(); i++) {
Poly poly = y(0, i).CRTInterpolate();
poly = poly.DivideAndRound(q);
}
for (size_t j = 0; j < poly.GetLength(); j++) {
output << poly.at(j);
}
template <class Element>
std::string LWEConjunctionCHCPRFAlgorithm<Element>::Evaluate(const shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> D, const std::string &input) const {
Matrix<Element> y = (*m_A)[0];
for (usint i = 0; i < m_adjustedLength; i++) {
std::string chunk = input.substr(i * m_chunkSize, m_chunkSize);
int k = std::stoi(chunk, nullptr, 2);
y = y * *(*D)[i][k];
}
return output.str();
return TransformMatrixToPRFOutput(y);
};
......@@ -306,6 +308,33 @@ shared_ptr<Matrix<Element>> LWEConjunctionCHCPRFAlgorithm<Element>::Encode(usint
};
template <class Element>
std::string LWEConjunctionCHCPRFAlgorithm<Element>::TransformMatrixToPRFOutput(const Matrix<Element> &matrix) const {
const BigInteger &q = m_elemParams->GetModulus();
const BigInteger &half = m_elemParams->GetModulus() >> 1;
std::stringstream output;
for (size_t i = 0; i < matrix.GetCols(); i++) {
Poly poly = matrix(0, i).CRTInterpolate();
// Transform negative numbers so that they could be rounded correctly
for (usint i = 0; i < poly.GetLength(); i++) {
if (poly[i] > half)
poly[i] = q - poly[i];
}
poly = poly.DivideAndRound(half);
for (size_t j = 0; j < poly.GetLength(); j++) {
output << poly.at(j);
}
}
return output.str();
}
}
#endif
......@@ -52,8 +52,6 @@ namespace lbcrypto {
class LWEConjunctionCHCPRFAlgorithm {
public:
typedef shared_ptr<vector<vector<shared_ptr<Matrix<Element>>>>> KeyType;
/**
* Constructor
*
......@@ -81,25 +79,34 @@ namespace lbcrypto {
*
* @return unconstrained PRF key
*/
KeyType KeyGen();
shared_ptr<vector<vector<Element>>> KeyGen();
/**