Skip to content

Commit

Permalink
Extensions to PSI Logic, Updated CI, and Bug Fixes
Browse files Browse the repository at this point in the history
Added support for processing queries with the NOT operator homomorphically.
Introduced the NOT Expr, and a corresponding inline NOT QueryExpr Within the weights, or CNF, framework:

Extensions to the ExpandOr() function to queries with NOT operators, via a new function negate()
New function Tidy() which eliminates duplicate columns in inner clauses, or columns and their negation in inner clauses that can be created by squashing ORs. It also eliminates empty clauses,
Put the code from build() which constructed the corresponding weights into a new function buildWeights(), and extended this to the case there are negations of columns
New framework which evaluates queries homomorphically directly from the string:
New function removeOr() within the QueryBuilder class which generates a new query string which is logically equivalent, but only has Ands and Nots
Overloaded contains() function that takes a string instead of a QueryType, and evaluates the RPN directly using a stack of ciphertexts
Updated CI

Deprecated build&test on Ubuntu 20.04
Updated build&test on Ubuntu 22.04
Added build&test on macOS 12 and MacOS 13
Bug Fix for unsafe use of sprintf

Co-authored-by: @TabOg
Co-authored-by: @jlhcrawford
Co-authored-by: @hamishun
Co-authored-by: @faberga
  • Loading branch information
faberga committed Jul 15, 2023
2 parents a7a7bbe + a48ca0b commit f6a5f90
Show file tree
Hide file tree
Showing 12 changed files with 956 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/github-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
package_build: [ON, OFF]
hexl: [ON, OFF]
c_compiler: [gcc, clang]
os: [macos-latest, ubuntu-20.04, ubuntu-22.04]
os: [macos-12, macos-13, ubuntu-22.04]
include: # Use g++ with gcc only and clang++ with clang only
- c_compiler: gcc
cxx_compiler: g++
Expand Down
2 changes: 1 addition & 1 deletion ci/install_deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ if [ "${RUNNER_OS%-*}" == "ubuntu" ]; then
sudo apt-get -yq --no-install-suggests --no-install-recommends install libgmp-dev libntl-dev bats
fi

if [ "${RUNNER_OS}" == "macos-latest" ]; then
if [ "${RUNNER_OS}" == "macos-latest" ] || [ "${RUNNER_OS}" == "macos-12" ] || [ "${RUNNER_OS}" == "macos-13" ] ; then
brew install ntl bats-core
fi

Expand Down
106 changes: 99 additions & 7 deletions include/helib/partialMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,18 @@
* See the License for the specific language governing permissions and
* limitations under the License. See accompanying LICENSE file.
*/

/* Copyright (C) 2022 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Extended HElib to support the Not operator in queries.
* Contributions include
*
* Added:
* Database:
* template <typename TXT2>
auto contains(const std::string& query_string, const Matrix<TXT2>&
query_data) const
*/
#ifndef HELIB_PARTIALMATCH_H
#define HELIB_PARTIALMATCH_H

Expand Down Expand Up @@ -230,27 +241,46 @@ class Database
{}

/**
* @brief Function for performing a database lookup given a query expression
* and query data.
* @brief Overloaded function for performing a database lookup given a query
* expression and query data.
* @tparam TXT2 The type of the query data, can be either a `Ctxt` or
* `Ptxt<BGV>`.
* @param lookup_query The lookup query expression to perform.
* @param query_data The lookup query data to compare with the database.
* @return A `Matrix<TXT2>` containing 1s and 0s in slots where there was a
* match or no match respectively.
* @return A `Matrix<TXT>` containing 1s and 0s in slots where there was a
* match or no match respectively. The return type `TXT` is `Ctxt` if either
* query of database is encrypted, and `Ptxt<BGV>` otherwise.
**/
template <typename TXT2>
auto contains(const QueryType& lookup_query,
const Matrix<TXT2>& query_data) const;

/**
* @brief Overloaded function for performing a database lookup given a query
* string and query data.
* @tparam TXT2 The type of the query data, can be either a `Ctxt` or
* `Ptxt<BGV>`.
* @param lookup_query A query string in Reverse Polish Notation with only
*`ANDs` and `NOTs`.
* @param query_data The lookup query data to compare with the database.
* @return A `Matrix<TXT>` containing 1s and 0s in slots where there was a
* match or no match respectively. The return type `TXT` is `Ctxt` if either
* query of database is encrypted, and `Ptxt<BGV>` otherwise.
**/
template <typename TXT2>
auto contains(const std::string& query_string,
const Matrix<TXT2>& query_data) const;

/**
* @brief Function for performing a weighted partial match given a query
* expression and query data.
* @tparam TXT2 The type of the query data, can be either a `Ctxt` or
* `Ptxt<BGV>`.
* @param weighted_query The weighted lookup query expression to perform.
* @param query_data The query data to compare with the database.
* @return A `Matrix<TXT2>` containing a score on weighted matches.
* @return A `Matrix<TXT>` containing a score on weighted matches. The return
* type `TXT` is `Ctxt` if either query of database is encrypted, and
* `Ptxt<BGV>` otherwise.
**/
template <typename TXT2>
auto getScore(const QueryType& weighted_query,
Expand All @@ -261,7 +291,7 @@ class Database
* @brief Returns number of columns in the database.
* @return The number of columns in the database.
**/
long columns() { return data.dims(1); }
long columns() const { return data.dims(1); }

Matrix<TXT>& getData();

Expand All @@ -270,6 +300,68 @@ class Database
std::shared_ptr<const Context> context;
};

template <typename TXT>
template <typename TXT2>
inline auto Database<TXT>::contains(const std::string& query_string,
const Matrix<TXT2>& query_data) const
{
// resolve type names: if both are ptxt, return ptxt, otherwise return ctxt
using RTXT = typename std::conditional<(std::is_same_v<TXT, Ptxt<BGV>>)&&(
std::is_same_v<TXT2, Ptxt<BGV>>),
Ptxt<BGV>,
Ctxt>::type;

auto mask = calculateMasks(context->getEA(), query_data, this->data);

std::istringstream input(query_string);

std::stack<Matrix<RTXT>> txtStack;
std::string symbol;

while (input >> symbol) {
if (symbol == "!") {
auto& top = txtStack.top();
top.apply([](auto& entry) { entry.negate(); });
top.apply([](auto& entry) { entry.addConstant(NTL::ZZX(1L)); });
} else if (symbol == "&&") {
auto rhs = txtStack.top();
txtStack.pop();

auto& lhs = txtStack.top();
lhs.template entrywiseOperation<RTXT>(
rhs,
[](auto& l, const auto& r) -> decltype(auto) {
l.multiplyBy(r);
return l;
});
} else {
// If symbol is ||, throw a specific error
assertFalse(symbol == "||",
"Cannot evaluate contains() on a string which contains Or "
"operator: first call removeOr()");
// Otherwise, verify symbol is a number
assertTrue(isNumber(symbol), "String is not a number: '" + symbol + "'");
// And verify the number is in [0,...,columns - 1]
assertTrue((std::stol(symbol) >= 0) &&
((std::stol(symbol) < this->columns())),
"column is out of range");
// push a copy of mask[symbol]. To take a deep copy, first make a matrix
// of the right type and dimension with zeroes in every entry.
auto ones(mask(0, 0));
ones.clear();
ones.addConstant(NTL::ZZX(0L));
Matrix<RTXT> col(ones, mask.dims(0), 1l);
// now add the entries we want to the RHS
col += mask.getColumn(std::stol(symbol));
txtStack.push(col);
}
}
assertEq<LogicError>(1UL,
txtStack.size(),
"Size of stack after evaluation should be 1");
return std::move(txtStack.top());
}

template <typename TXT>
template <typename TXT2>
inline auto Database<TXT>::contains(const QueryType& lookup_query,
Expand Down
Loading

0 comments on commit f6a5f90

Please sign in to comment.