Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of the initialization, setup, and execution phase of the reach-only protocol. #1129

Merged
merged 10 commits into from
Aug 4, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "wfa/measurement/common/crypto/encryption_utility_helper.h"

#include <memory>
#include <utility>

#include "absl/status/status.h"
Expand Down Expand Up @@ -67,6 +68,26 @@ absl::StatusOr<std::vector<std::string>> GetBlindedRegisterIndexes(
return blinded_register_indexes;
}

absl::StatusOr<std::vector<std::string>> GetRollv2BlindedRegisterIndexes(
absl::string_view data, ProtocolCryptor& protocol_cryptor) {
ASSIGN_OR_RETURN(size_t register_count,
GetNumberOfBlocks(data, kBytesPerCipherText));
std::vector<std::string> blinded_register_indexes;
blinded_register_indexes.reserve(register_count);
for (size_t index = 0; index < register_count; ++index) {
// The size of data_block is guaranteed to be equal to
// kBytesPerCipherText
absl::string_view data_block =
data.substr(index * kBytesPerCipherText, kBytesPerCipherText);
ASSIGN_OR_RETURN(ElGamalCiphertext ciphertext,
ExtractElGamalCiphertextFromString(data_block));
ASSIGN_OR_RETURN(std::string decrypted_el_gamal,
protocol_cryptor.DecryptLocalElGamal(ciphertext));
blinded_register_indexes.push_back(std::move(decrypted_el_gamal));
}
return blinded_register_indexes;
}

absl::StatusOr<KeyCountPairCipherText> ExtractKeyCountPairFromSubstring(
absl::string_view str) {
if (str.size() != kBytesPerCipherText * 2) {
Expand Down Expand Up @@ -121,6 +142,17 @@ absl::Status WriteEcPointPairToString(const ElGamalEcPointPair& ec_point_pair,
return absl::OkStatus();
}

absl::StatusOr<ElGamalEcPointPair> GetEcPointPairFromString(
absl::string_view str, int curve_id) {
std::unique_ptr<Context> context(new Context);
ASSIGN_OR_RETURN(ECGroup ec_group, ECGroup::Create(curve_id, context.get()));
ASSIGN_OR_RETURN(ElGamalCiphertext ciphertext,
ExtractElGamalCiphertextFromString(str));
ASSIGN_OR_RETURN(ElGamalEcPointPair ec_point,
GetElGamalEcPoints(ciphertext, ec_group));
return ec_point;
}

absl::StatusOr<std::vector<std::string>> GetCountValuesPlaintext(
int maximum_value, int curve_id) {
if (maximum_value < 1) {
Expand All @@ -142,4 +174,31 @@ absl::StatusOr<std::vector<std::string>> GetCountValuesPlaintext(
return result;
}

absl::Status EncryptCompositeElGamalAndAppendToString(
ProtocolCryptor& protocol_cryptor, CompositeType composite_type,
absl::string_view plaintext_ec, std::string& data) {
ASSIGN_OR_RETURN(
ElGamalCiphertext key,
protocol_cryptor.EncryptCompositeElGamal(plaintext_ec, composite_type));
data.append(key.first);
data.append(key.second);
return absl::OkStatus();
}

absl::Status EncryptCompositeElGamalAndWriteToString(
ProtocolCryptor& protocol_cryptor, CompositeType composite_type,
absl::string_view plaintext_ec, size_t pos, std::string& result) {
if (pos + kBytesPerCipherText > result.size()) {
return absl::InvalidArgumentError("result is not long enough to write.");
}
ASSIGN_OR_RETURN(
ElGamalCiphertext key,
protocol_cryptor.EncryptCompositeElGamal(plaintext_ec, composite_type));

result.replace(pos, kBytesPerEcPoint, key.first);
result.replace(pos + kBytesPerEcPoint, kBytesPerEcPoint, key.second);

return absl::OkStatus();
}

} // namespace wfa::measurement::common::crypto
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

namespace wfa::measurement::common::crypto {

using ::wfa::measurement::common::crypto::CompositeType;

// A pair of ciphertexts which store the key and count values of a liquidlegions
// register.
struct KeyCountPairCipherText {
Expand All @@ -46,6 +48,11 @@ absl::StatusOr<ElGamalCiphertext> ExtractElGamalCiphertextFromString(
absl::StatusOr<std::vector<std::string>> GetBlindedRegisterIndexes(
absl::string_view data, ProtocolCryptor& protocol_cryptor);

// Blinds the last layer of ElGamal Encryption of register indexes, and return
// the deterministically encrypted results.
absl::StatusOr<std::vector<std::string>> GetRollv2BlindedRegisterIndexes(
absl::string_view data, ProtocolCryptor& protocol_cryptor);

// Extracts a KeyCountPairCipherText from a string_view.
absl::StatusOr<KeyCountPairCipherText> ExtractKeyCountPairFromSubstring(
absl::string_view str);
Expand All @@ -66,10 +73,30 @@ absl::Status AppendEcPointPairToString(const ElGamalEcPointPair& ec_point_pair,
absl::Status WriteEcPointPairToString(const ElGamalEcPointPair& ec_point_pair,
size_t pos, std::string& result);

// Extract a ElGamalEcPointPair from a string_view.
absl::StatusOr<ElGamalEcPointPair> GetEcPointPairFromString(
absl::string_view str, int curve_id);

// Returns the vector of ECPoints for count values from 1 to maximum_value.
absl::StatusOr<std::vector<std::string>> GetCountValuesPlaintext(
int maximum_value, int curve_id);

// Encrypts plaintext and appends bytes of the cipher text to a target string.
// The length of bytes appened is kBytesPerCipherText = kBytesPerEcPoint * 2.
absl::Status EncryptCompositeElGamalAndAppendToString(
ProtocolCryptor& protocol_cryptor, CompositeType composite_type,
absl::string_view plaintext_ec, std::string& data);

// Encrypts plaintext and writes bytes of the cipher text to a target string at
// a certain position.
// Bytes are written by replacing content of the string starting at pos. The
// length of bytes written is kBytesPerCipherText = kBytesPerEcPoint * 2.
// Returns a Status with code `INVALID_ARGUMENT` when the result string is not
// long enough.
absl::Status EncryptCompositeElGamalAndWriteToString(
ProtocolCryptor& protocol_cryptor, CompositeType composite_type,
absl::string_view plaintext_ec, size_t pos, std::string& result);

} // namespace wfa::measurement::common::crypto

#endif // SRC_MAIN_CC_WFA_MEASUREMENT_COMMON_CRYPTO_ENCRYPTION_UTILITY_HELPER_H_
37 changes: 37 additions & 0 deletions src/main/cc/wfa/measurement/common/crypto/protocol_cryptor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class ProtocolCryptorImpl : public ProtocolCryptor {
CompositeType composite_type) override;
absl::StatusOr<ElGamalCiphertext> EncryptCompositeElGamal(
absl::string_view plain_ec_point, CompositeType composite_type) override;
absl::StatusOr<std::string> EncryptIntegerWithCompositElGamalAndWriteToString(
int64_t value) override;
absl::StatusOr<ElGamalCiphertext> ReRandomize(
const ElGamalCiphertext& ciphertext,
CompositeType composite_type) override;
Expand Down Expand Up @@ -173,6 +175,41 @@ absl::StatusOr<ElGamalCiphertext> ProtocolCryptorImpl::EncryptCompositeElGamal(
: partial_composite_el_gamal_cipher_->Encrypt(plain_ec_point);
}

absl::StatusOr<std::string>
ProtocolCryptorImpl::EncryptIntegerWithCompositElGamalAndWriteToString(
int64_t value) {
Context ctx;
std::string ciphertext;
ciphertext.resize(kBytesPerCipherText);
if (value < 0) {
return absl::InvalidArgumentError(
absl::StrCat("The value should be non-negative, but is ", value));
}
if (value == 0) {
ASSIGN_OR_RETURN(
ElGamalEcPointPair zero_ec,
EncryptIdentityElementToEcPointsCompositeElGamal(CompositeType::kFull));
std::string temp;
ASSIGN_OR_RETURN(temp, zero_ec.u.ToBytesCompressed());
ciphertext.replace(0, kBytesPerEcPoint, temp);
ASSIGN_OR_RETURN(temp, zero_ec.e.ToBytesCompressed());
ciphertext.replace(kBytesPerEcPoint, kBytesPerEcPoint, temp);
} else {
ASSIGN_OR_RETURN(ElGamalEcPointPair one_ec,
EncryptPlaintextToEcPointsCompositeElGamal(
kUnitECPointSeed, CompositeType::kFull));
ASSIGN_OR_RETURN(
ElGamalEcPointPair point_ec,
MultiplyEcPointPairByScalar(one_ec, ctx.CreateBigNum(value)));
std::string temp;
ASSIGN_OR_RETURN(temp, point_ec.u.ToBytesCompressed());
ciphertext.replace(0, kBytesPerEcPoint, temp);
ASSIGN_OR_RETURN(temp, point_ec.e.ToBytesCompressed());
ciphertext.replace(kBytesPerEcPoint, kBytesPerEcPoint, temp);
}
return ciphertext;
}

absl::StatusOr<ElGamalCiphertext> ProtocolCryptorImpl::ReRandomize(
const ElGamalCiphertext& ciphertext, CompositeType composite_type) {
ASSIGN_OR_RETURN(
Expand Down
3 changes: 3 additions & 0 deletions src/main/cc/wfa/measurement/common/crypto/protocol_cryptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class ProtocolCryptor {
// Encrypts the plain EcPoint using the full or partial composite ElGamal Key.
virtual absl::StatusOr<ElGamalCiphertext> EncryptCompositeElGamal(
absl::string_view plain_ec_point, CompositeType composite_type) = 0;
// Encrypts an integer with the full composite ElGamal Key.
virtual absl::StatusOr<std::string>
EncryptIntegerWithCompositElGamalAndWriteToString(int64_t value) = 0;
// Encrypts the Identity Element using the full or partial composite ElGamal
// Key, returns the result as an ElGamalEcPointPair.
virtual absl::StatusOr<ElGamalEcPointPair>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@ package(default_visibility = [

_INCLUDE_PREFIX = "/src/main/cc"

cc_library(
name = "liquid_legions_v2_encryption_utility_helper",
srcs = [
"liquid_legions_v2_encryption_utility_helper.cc",
],
hdrs = [
"liquid_legions_v2_encryption_utility_helper.h",
],
strip_include_prefix = _INCLUDE_PREFIX,
deps = [
"//src/main/proto/wfa/measurement/internal/duchy:crypto_cc_proto",
"//src/main/proto/wfa/measurement/internal/duchy:differential_privacy_cc_proto",
"@any_sketch//src/main/cc/any_sketch/crypto:sketch_encrypter",
"@any_sketch//src/main/cc/estimation:estimators",
"@com_google_absl//absl/status:statusor",
],
)

cc_library(
name = "liquid_legions_v2_encryption_utility",
srcs = [
Expand All @@ -19,6 +37,7 @@ cc_library(
],
strip_include_prefix = _INCLUDE_PREFIX,
deps = [
":liquid_legions_v2_encryption_utility_helper",
":multithreading_helper",
":noise_parameters_computation",
"//src/main/cc/wfa/measurement/common/crypto:constants",
Expand All @@ -36,6 +55,34 @@ cc_library(
],
)

cc_library(
name = "reach_only_liquid_legions_v2_encryption_utility",
srcs = [
"reach_only_liquid_legions_v2_encryption_utility.cc",
],
hdrs = [
"reach_only_liquid_legions_v2_encryption_utility.h",
],
strip_include_prefix = _INCLUDE_PREFIX,
deps = [
":liquid_legions_v2_encryption_utility_helper",
":multithreading_helper",
":noise_parameters_computation",
"//src/main/cc/wfa/measurement/common/crypto:constants",
"//src/main/cc/wfa/measurement/common/crypto:encryption_utility_helper",
"//src/main/cc/wfa/measurement/common/crypto:protocol_cryptor",
"//src/main/proto/wfa/measurement/internal/duchy/protocol:reach_only_liquid_legions_v2_encryption_methods_cc_proto",
"@any_sketch//src/main/cc/estimation:estimators",
"@any_sketch//src/main/cc/math:distributed_discrete_gaussian_noiser",
"@any_sketch//src/main/cc/math:distributed_geometric_noiser",
"@com_google_absl//absl/algorithm:container",
"@com_google_private_join_and_compute//private_join_and_compute/crypto:commutative_elgamal",
"@wfa_common_cpp//src/main/cc/common_cpp/jni:jni_wrap",
"@wfa_common_cpp//src/main/cc/common_cpp/macros",
"@wfa_common_cpp//src/main/cc/common_cpp/time:started_thread_cpu_timer",
],
)

cc_library(
name = "liquid_legions_v2_encryption_utility_wrapper",
srcs = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,39 +240,6 @@ absl::StatusOr<std::vector<ElGamalEcPointPair>> GetSameKeyAggregatorMatrixBase(
return std::move(result);
}

absl::Status EncryptCompositeElGamalAndAppendToString(
ProtocolCryptor& protocol_cryptor, CompositeType composite_type,
absl::string_view plaintext_ec, std::string& data) {
ASSIGN_OR_RETURN(
ElGamalCiphertext key,
protocol_cryptor.EncryptCompositeElGamal(plaintext_ec, composite_type));
data.append(key.first);
data.append(key.second);
return absl::OkStatus();
}

// Encrypts plaintext and writes bytes of the cipher text to a target string at
// a certain position.
// Bytes are written by replacing content of the string starting at pos. The
// length of bytes written is kBytesPerCipherText = kBytesPerEcPoint * 2.
// Returns a Status with code `INVALID_ARGUMENT` when the result string is not
// long enough.
absl::Status EncryptCompositeElGamalAndWriteToString(
ProtocolCryptor& protocol_cryptor, CompositeType composite_type,
absl::string_view plaintext_ec, size_t pos, std::string& result) {
if (pos + kBytesPerCipherText > result.size()) {
return absl::InvalidArgumentError("result is not long enough to write.");
}
ASSIGN_OR_RETURN(
ElGamalCiphertext key,
protocol_cryptor.EncryptCompositeElGamal(plaintext_ec, composite_type));

result.replace(pos, kBytesPerEcPoint, key.first);
result.replace(pos + kBytesPerEcPoint, kBytesPerEcPoint, key.second);

return absl::OkStatus();
}

// Adds encrypted blinded-histogram-noise registers to the end of data.
// returns the number of such noise registers added.
absl::StatusOr<int64_t> AddBlindedHistogramNoise(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2023 The Cross-Media Measurement Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "wfa/measurement/internal/duchy/protocol/liquid_legions_v2/liquid_legions_v2_encryption_utility_helper.h"

#include "estimation/estimators.h"

namespace wfa::measurement::internal::duchy::protocol::liquid_legions_v2 {

using ::wfa::any_sketch::Sketch;
using ::wfa::any_sketch::SketchConfig;
using ::wfa::measurement::internal::duchy::ElGamalPublicKey;

::wfa::any_sketch::crypto::ElGamalPublicKey ToAnySketchElGamalKey(
ElGamalPublicKey key) {
::wfa::any_sketch::crypto::ElGamalPublicKey result;
result.set_generator(key.generator());
result.set_element(key.element());
return result;
}

ElGamalPublicKey ToCmmsElGamalKey(
::wfa::any_sketch::crypto::ElGamalPublicKey key) {
ElGamalPublicKey result;
result.set_generator(key.generator());
result.set_element(key.element());
return result;
}

Sketch CreateEmptyLiquidLegionsSketch() {
Sketch plain_sketch;
plain_sketch.mutable_config()->add_values()->set_aggregator(
SketchConfig::ValueSpec::UNIQUE);
plain_sketch.mutable_config()->add_values()->set_aggregator(
SketchConfig::ValueSpec::SUM);
return plain_sketch;
}

Sketch CreateReachOnlyEmptyLiquidLegionsSketch() {
Sketch plain_sketch;
return plain_sketch;
}

DifferentialPrivacyParams MakeDifferentialPrivacyParams(double epsilon,
double delta) {
DifferentialPrivacyParams params;
params.set_epsilon(epsilon);
params.set_delta(delta);
return params;
}

} // namespace wfa::measurement::internal::duchy::protocol::liquid_legions_v2
Loading