Commit 85145d1e authored by Vasilii Sukhanov's avatar Vasilii Sukhanov Committed by Commit Bot

Add private-join-and-compute to third_party.

The code is a subset of the library containing ECCommutativeCipher. Unused
files were removed. The rest is modified to exclude unnecessary dependencies.

The library is branched at 375be83109e10b32441483dbd0f1ac493488d197.

Bug: 986298
Change-Id: I3c15cc994b493182e2b7b7661ace2efa339f538f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1720874Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Vasilii Sukhanov <vasilii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#685495}
parent 07217619
......@@ -45,6 +45,7 @@ jumbo_source_set("leak_detection") {
"//base",
"//components/password_manager/core/common",
"//components/signin/public/identity_manager",
"//third_party/private-join-and-compute/src:ec_commutative_cipher",
"//url",
]
}
......
Name: Private Join and Compute subset
Short Name: private-join-and-compute
URL: https://github.com/google/private-join-and-compute
Version: 0
Date: Jun 27 2019
Revision: 375be83109e10b32441483dbd0f1ac493488d197
License: Apache 2.0
License File: LICENSE
Security Critical: yes
Description:
The package contains a communicative cipher. It's used to communicate with the leak detection Google server.
Local Modifications:
Stripped all the dependencies except for BoringSSL. chromium_patch.h is the only new file. Other modifications are removing the includes, fixing the macroses to those used in Chrome and removing unused functions and classes. The diff files are in order of modifications:
files.diff - the files deleted from the original library.
dependencies.diff - removes all the dependencies on Abseil and other libraries replacing them with Chrome's analogues.
compilation.diff - fixes compilation/static analyzers in Chrome.
fix_nulls.diff - makes the presubmit happy by replacing NULL with nullptr.
# Private Join and Compute
This project contains an implementation of the "Private Join and Compute"
functionality. This functionality allows two users, each holding an input file,
to privately compute the sum of associated values for records that have common
identifiers.
In more detail, suppose a Server has a file containing the following
identifiers:
Identifiers |
----------- |
Sam |
Ada |
Ruby |
Brendan |
And a Client has a file containing the following identifiers, paired with
associated integer values:
Identifiers | Associated Values
----------- | -----------------
Ruby | 10
Ada | 30
Alexander | 5
Mika | 35
Then the Private Join and Compute functionality would allow the Client to learn
that the input files had *2* identifiers in common, and that the associated
values summed to *40*. It does this *without* revealing which specific
identifiers were in common (Ada and Ruby in the example above), or revealing
anything additional about the other identifiers in the two parties' data set.
Private Join and Compute is a variant of the well-studied Private Set
Intersection functionality. We sometimes also refer to Private Join and Compute
as Private Intersection-Sum.
## How to run the protocol
In order to run Private Join and Compute, you need to install Bazel, if you
don't have it already.
[Follow the instructions for your platform on the Bazel website.](https://docs.bazel.build/versions/master/install.html)
You also need to install Git, if you don't have it already.
[Follow the instructions for your platform on the Git website.](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
Once you've installed Bazel and Git, open a Terminal and clone the Private Join
and Compute repository into a local folder:
```shell
git clone https://github.com/google/private-join-and-compute.git
```
Navigate into the `private-join-and-compute` folder you just created, and build
the Private Join and Compute library and dependencies using Bazel:
```bash
cd private-join-and-compute
bazel build :all
```
If you get an error, you may need to build with the following flags:
```bash
bazel build :all --incompatible_disable_deprecated_attr_params=false --incompatible_depset_is_not_iterable=false --incompatible_new_actions_api=false --incompatible_no_support_tools_in_action_inputs=false
```
(All the following instructions must be run from inside the
private-join-and-compute folder.)
Next, generate some dummy data to run the protocol on:
```shell
bazel-bin/generate_dummy_data --server_data_file=/tmp/dummy_server_data.csv \
--client_data_file=/tmp/dummy_client_data.csv
```
This will create dummy data for the server and client at the specified
locations. You can look at the files in `/tmp/dummy_server_data.csv` and
`/tmp/dummy_client_data.csv` to see the dummy data that was generated. You can
also change the size of the dummy data generated using additional flags. For
example:
```shell
bazel-bin/generate_dummy_data \
--server_data_file=/tmp/dummy_server_data.csv \
--client_data_file=/tmp/dummy_client_data.csv --server_data_size=1000 \
--client_data_size=1000 --intersection_size=200 --max_associated_value=100
```
Once you've generated dummy data, you can start the server as follows:
```shell
bazel-bin/server --server_data_file=/tmp/dummy_server_data.csv
```
The server will load data from the specified file, and wait for a connection
from the client.
Once the server is running, you can start a client to connect to the server.
Create a new terminal and navigate to the private-join-and-compute folder. Once
there, run the following command to start the client:
```shell
bazel-bin/client --client_data_file=/tmp/dummy_client_data.csv
```
The client will connect to the server and execute the steps of the protocol
sequentially. At the end of the protocol, the client will output the
Intersection Size (the number of identifiers in common) and the Intersection Sum
(the sum of associated values). If the protocol was successful, both the server
and client will shut down.
## Caveats
Several caveats should be carefully considered before using Private Join and
Compute.
### Security Model
Our protocol has security against honest-but-curious adversaries. This means
that as long as both participants follow the protocol honestly, neither will
learn more than the size of the intersection and the intersection-sum. However,
if a participant deviates from the protocol, it is possible they could learn
more than the prescribed information. For example, they could learn the specific
identifiers in the intersection. If the underlying data is sensitive, we
recommend performing a careful risk analysis before using Private Join and
Compute, to ensure that neither party has an incentive to deviate from the
protocol. The protocol can also be supplemented with external enforcement such
as code audits to ensure that no party deviates from the protocol.
### Maliciously Chosen Inputs
We note that our protocol does not authenticate that parties use "real" input,
nor does it prevent them from arbitrarily changing their input. We suggest
careful analysis of whether any party has an incentive to lie about their
inputs. This risk can also be mitigated by external enforcement such as code
audits.
### Leakage from the Intersection-Sum.
While the Private Join and Compute functionality is supposed to reveal only the
intersection-size and intersection-sum, it is possible that the intersection-sum
itself could reveal something about which identifiers were in common.
For example, if an identifier has a very unique associated integer values, then
it may be easy to detect if that identifier was in the intersection simply by
looking at the intersection-sum. One way this could happen is if one of the
identifiers has a very large associated value compared to all other identifiers.
In that case, if the intersection-sum is large, one could reasonably infer that
that identifier was in the intersection. To mitigate this, we suggest scrubbing
inputs to remove identifiers with "outlier" values.
Another way that the intersection-sum may leak which identifiers are in the
intersection is if the intersection is too small. This could make it easier to
guess which combination of identifiers could be in the intersection in order to
yield a particular intersection-sum. To mitigate this, one could abort the
protocol if the intersection-size is below a certain threshold, or to add noise
to the output of the protocol.
(Note that these mitigations are not currently implemented in this open-source
library.)
## Disclaimers
This is not an officially supported Google product. The software is provided
as-is without any guarantees or warranties, express or implied.
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/crypto/context.cc third_party/private-join-and-compute/crypto/context.cc
--- /tmp/private-join-and-compute.original/crypto/context.cc 2019-08-06 16:15:39.918264597 +0200
+++ third_party/private-join-and-compute/crypto/context.cc 2019-08-07 12:42:02.483051443 +0200
@@ -41,10 +37,6 @@
one_bn_(CreateBigNum(1)),
two_bn_(CreateBigNum(2)),
three_bn_(CreateBigNum(3)) {
-#if defined(OS_NACL)
- nacl::SeedOpenSSLRand();
-#endif
- OpenSSLInit();
CHECK(RAND_status()) << "OpenSSL PRNG is not properly seeded.";
HMAC_CTX_init(&hmac_ctx_);
}
@@ -127,7 +119,7 @@
BigNum Context::PRF(const std::string& key, const std::string& data,
const BigNum& max_value) {
- CHECK_GE(key.size() * 8, 80);
+ CHECK_GE(key.size() * 8, 80u);
CHECK_LE(max_value.BitLength(), 512)
<< "The requested output length is not supported. The maximum "
"supported output length is 512. The requested output length is "
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/crypto/ec_commutative_cipher.cc third_party/private-join-and-compute/crypto/ec_commutative_cipher.cc
--- /tmp/private-join-and-compute.original/crypto/ec_commutative_cipher.cc 2019-08-07 14:21:57.192714845 +0200
+++ third_party/private-join-and-compute/crypto/ec_commutative_cipher.cc 2019-08-07 12:42:02.483051443 +0200
@@ -93,25 +93,6 @@
return point.Mul(private_key_);
}
-StatusOr<std::pair<std::string, std::string>>
-ECCommutativeCipher::ReEncryptElGamalCiphertext(
- const std::pair<std::string, std::string>& elgamal_ciphertext) const {
- ASSIGN_OR_RETURN(ECPoint u, group_.CreateECPoint(elgamal_ciphertext.first));
- ASSIGN_OR_RETURN(ECPoint e, group_.CreateECPoint(elgamal_ciphertext.second));
-
- elgamal::Ciphertext decoded_ciphertext = {std::move(u), std::move(e)};
-
- ASSIGN_OR_RETURN(elgamal::Ciphertext reencrypted_ciphertext,
- elgamal::Exp(decoded_ciphertext, private_key_));
-
- ASSIGN_OR_RETURN(std::string serialized_u,
- reencrypted_ciphertext.u.ToBytesCompressed());
- ASSIGN_OR_RETURN(std::string serialized_e,
- reencrypted_ciphertext.e.ToBytesCompressed());
-
- return std::make_pair(std::move(serialized_u), std::move(serialized_e));
-}
-
StatusOr<std::string> ECCommutativeCipher::Decrypt(
const std::string& ciphertext) const {
ASSIGN_OR_RETURN(ECPoint point, group_.CreateECPoint(ciphertext));
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/crypto/ec_commutative_cipher.h third_party/private-join-and-compute/crypto/ec_commutative_cipher.h
--- /tmp/private-join-and-compute.original/crypto/ec_commutative_cipher.h 2019-08-07 14:21:57.192714845 +0200
+++ third_party/private-join-and-compute/crypto/ec_commutative_cipher.h 2019-08-07 12:42:02.483051443 +0200
@@ -139,16 +139,6 @@
::private_join_and_compute::StatusOr<std::string> ReEncrypt(
const std::string& ciphertext) const;
- // Encrypts an ElGamal ciphertext with the private key.
- //
- // Returns an INVALID_ARGUMENT error code if the input is not a valid encoding
- // of an ElGamal ciphertext on this curve as defined in ANSI X9.62 ECDSA.
- //
- // The result is another ElGamal ciphertext, encoded in compressed form.
- ::private_join_and_compute::StatusOr<std::pair<std::string, std::string>>
- ReEncryptElGamalCiphertext(
- const std::pair<std::string, std::string>& elgamal_ciphertext) const;
-
// Decrypts an encoded point with the private key.
//
// Returns an INVALID_ARGUMENT error code if the input is not a valid encoding
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/util/status.cc third_party/private-join-and-compute/util/status.cc
--- /tmp/private-join-and-compute.original/util/status.cc 2019-08-06 16:15:39.922264595 +0200
+++ third_party/private-join-and-compute/util/status.cc 2019-08-07 12:42:02.483051443 +0200
@@ -20,26 +20,6 @@
namespace private_join_and_compute {
-namespace {
-
-const Status& GetOk() {
- static const Status* status = new Status();
- return *status;
-}
-
-const Status& GetCancelled() {
- static const Status* status =
- new Status(private_join_and_compute::StatusCode::kCancelled, "");
- return *status;
-}
-
-const Status& GetUnknown() {
- static const Status* status = new Status(private_join_and_compute::StatusCode::kUnknown, "");
- return *status;
-}
-
-} // namespace
-
Status::Status() : code_(private_join_and_compute::StatusCode::kOk), message_("") {}
Status::Status(private_join_and_compute::StatusCode error, std::string error_message)
@@ -58,10 +38,6 @@
return *this;
}
-const Status& Status::OK = GetOk();
-const Status& Status::CANCELLED = GetCancelled();
-const Status& Status::UNKNOWN = GetUnknown();
-
std::string Status::ToString() const {
if (code_ == private_join_and_compute::StatusCode::kOk) {
return "OK";
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/util/status.h third_party/private-join-and-compute/util/status.h
--- /tmp/private-join-and-compute.original/util/status.h 2019-08-06 16:15:39.922264595 +0200
+++ third_party/private-join-and-compute/util/status.h 2019-08-07 12:42:02.483051443 +0200
@@ -54,9 +54,12 @@
Status& operator=(const Status& other);
// Some pre-defined Status objects
- static const Status& OK; // NOLINT // Identical to 0-arg constructor
- static const Status& CANCELLED; // NOLINT
- static const Status& UNKNOWN; // NOLINT
+ static Status OK() {
+ return Status();
+ }
+ static Status UNKNOWN() {
+ return Status(private_join_and_compute::StatusCode::kUnknown, "");
+ }
// Accessors
bool ok() const { return code_ == private_join_and_compute::StatusCode::kOk; }
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/util/statusor.h third_party/private-join-and-compute/util/statusor.h
--- /tmp/private-join-and-compute.original/util/statusor.h 2019-08-06 16:15:39.922264595 +0200
+++ third_party/private-join-and-compute/util/statusor.h 2019-08-07 12:42:02.939051124 +0200
@@ -177,7 +177,7 @@
} // namespace internal
template <typename T>
-inline StatusOr<T>::StatusOr() : status_(Status::UNKNOWN), value_(nullptr) {}
+inline StatusOr<T>::StatusOr() : status_(Status::UNKNOWN()), value_(nullptr) {}
template <typename T>
inline StatusOr<T>::StatusOr(const Status& status)
@@ -189,7 +189,7 @@
template <typename T>
inline StatusOr<T>::StatusOr(const T& value)
- : status_(Status::OK), value_(new T(value)) {
+ : status_(Status::OK()), value_(new T(value)) {
if (internal::StatusOrHelper::Specialize<T>::IsValueNull(*value_)) {
status_ = internal::StatusOrHelper::HandleNullObjectCtorArg();
}
@@ -209,7 +209,7 @@
template <typename T>
inline StatusOr<T>::StatusOr(T&& value)
- : status_(Status::OK), value_(new T(std::forward<T>(value))) {
+ : status_(Status::OK()), value_(new T(std::forward<T>(value))) {
if (internal::StatusOrHelper::Specialize<T>::IsValueNull(*value_)) {
status_ = internal::StatusOrHelper::HandleNullObjectCtorArg();
}
This diff is collapsed.
Only in /tmp/private-join-and-compute.original: BUILD
Only in third_party/private-join-and-compute: BUILD.gn
Only in third_party/private-join-and-compute: chromium_patch.h
Only in /tmp/private-join-and-compute.original: client.cc
Only in /tmp/private-join-and-compute.original: client_impl.cc
Only in /tmp/private-join-and-compute.original: client_impl.h
Files /tmp/private-join-and-compute.original/crypto/big_num.cc and third_party/private-join-and-compute/crypto/big_num.cc differ
Files /tmp/private-join-and-compute.original/crypto/big_num.h and third_party/private-join-and-compute/crypto/big_num.h differ
Only in /tmp/private-join-and-compute.original/crypto: BUILD
Files /tmp/private-join-and-compute.original/crypto/context.cc and third_party/private-join-and-compute/crypto/context.cc differ
Files /tmp/private-join-and-compute.original/crypto/context.h and third_party/private-join-and-compute/crypto/context.h differ
Files /tmp/private-join-and-compute.original/crypto/ec_commutative_cipher.cc and third_party/private-join-and-compute/crypto/ec_commutative_cipher.cc differ
Files /tmp/private-join-and-compute.original/crypto/ec_commutative_cipher.h and third_party/private-join-and-compute/crypto/ec_commutative_cipher.h differ
Files /tmp/private-join-and-compute.original/crypto/ec_group.cc and third_party/private-join-and-compute/crypto/ec_group.cc differ
Files /tmp/private-join-and-compute.original/crypto/ec_point.cc and third_party/private-join-and-compute/crypto/ec_point.cc differ
Only in /tmp/private-join-and-compute.original/crypto: elgamal.cc
Only in /tmp/private-join-and-compute.original/crypto: elgamal.h
Only in /tmp/private-join-and-compute.original/crypto: fixed_base_exp.cc
Only in /tmp/private-join-and-compute.original/crypto: fixed_base_exp.h
Only in /tmp/private-join-and-compute.original/crypto: mont_mul.cc
Only in /tmp/private-join-and-compute.original/crypto: mont_mul.h
Only in /tmp/private-join-and-compute.original/crypto: openssl_init.cc
Only in /tmp/private-join-and-compute.original/crypto: openssl_init.h
Only in /tmp/private-join-and-compute.original/crypto: paillier.cc
Only in /tmp/private-join-and-compute.original/crypto: paillier.h
Only in /tmp/private-join-and-compute.original/crypto: two_modulus_crt.cc
Only in /tmp/private-join-and-compute.original/crypto: two_modulus_crt.h
Only in /tmp/private-join-and-compute.original: data_util.cc
Only in /tmp/private-join-and-compute.original: data_util.h
Only in third_party/private-join-and-compute: DEPS
Only in /tmp/private-join-and-compute.original: generate_dummy_data.cc
Only in /tmp/private-join-and-compute.original: .git
Only in /tmp/private-join-and-compute.original: glog_files
Only in /tmp/private-join-and-compute.original: match.proto
Only in /tmp/private-join-and-compute.original: message_sink.h
Only in third_party/private-join-and-compute: OWNERS
Only in /tmp/private-join-and-compute.original: private_intersection_sum.proto
Only in /tmp/private-join-and-compute.original: private_join_and_compute.proto
Only in /tmp/private-join-and-compute.original: private_join_and_compute_rpc_impl.cc
Only in /tmp/private-join-and-compute.original: private_join_and_compute_rpc_impl.h
Only in /tmp/private-join-and-compute.original: protocol_client.h
Only in /tmp/private-join-and-compute.original: protocol_server.h
Only in third_party/private-join-and-compute: README.chromium
Only in /tmp/private-join-and-compute.original: server.cc
Only in /tmp/private-join-and-compute.original: server_impl.cc
Only in /tmp/private-join-and-compute.original: server_impl.h
Only in /tmp/private-join-and-compute.original/util: BUILD
Files /tmp/private-join-and-compute.original/util/status.cc and third_party/private-join-and-compute/util/status.cc differ
Files /tmp/private-join-and-compute.original/util/status.h and third_party/private-join-and-compute/util/status.h differ
Files /tmp/private-join-and-compute.original/util/status_macros.h and third_party/private-join-and-compute/util/status_macros.h differ
Files /tmp/private-join-and-compute.original/util/statusor.cc and third_party/private-join-and-compute/util/statusor.cc differ
Files /tmp/private-join-and-compute.original/util/statusor.h and third_party/private-join-and-compute/util/statusor.h differ
Only in /tmp/private-join-and-compute.original: WORKSPACE
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/util/statusor.cc third_party/private-join-and-compute/util/statusor.cc
--- /tmp/private-join-and-compute.original/util/statusor.cc 2019-08-07 14:21:57.196714841 +0200
+++ third_party/private-join-and-compute/util/statusor.cc 2019-08-07 12:42:02.939051124 +0200
@@ -24,7 +24,7 @@
static const char* kInvalidStatusCtorArgMessage =
"Status::OK is not a valid constructor argument to StatusOr<T>";
static const char* kNullObjectCtorArgMessage =
- "NULL is not a valid constructor argument to StatusOr<T*>";
+ "nullptr is not a valid constructor argument to StatusOr<T*>";
Status StatusOrHelper::HandleInvalidStatusCtorArg() {
LOG(DFATAL) << kInvalidStatusCtorArgMessage;
diff -ur --strip-trailing-cr /tmp/private-join-and-compute.original/util/statusor.h third_party/private-join-and-compute/util/statusor.h
--- /tmp/private-join-and-compute.original/util/statusor.h 2019-08-07 14:26:10.384523517 +0200
+++ third_party/private-join-and-compute/util/statusor.h 2019-08-07 12:42:02.939051124 +0200
@@ -96,15 +96,15 @@
StatusOr(const Status& status); // NOLINT - no explicit
// Construct a new StatusOr with the given value. If T is a plain pointer,
- // value must not be NULL. After calling this constructor, calls to
+ // value must not be nullptr. After calling this constructor, calls to
// ValueOrDie() will succeed, and calls to status() will return OK.
//
// NOTE: Not explicit - we want to use StatusOr<T> as a return type
// so it is convenient and sensible to be able to do 'return T()'
// when the return type is StatusOr<T>.
//
- // REQUIRES: if T is a plain pointer, value != NULL. This requirement is
- // DCHECKed. In optimized builds, passing a NULL pointer here will have
+ // REQUIRES: if T is a plain pointer, value != nullptr. This requirement is
+ // DCHECKed. In optimized builds, passing a nullptr pointer here will have
// the effect of passing ::private_join_and_compute::StatusCode::kInternal as a fallback.
StatusOr(const T& value); // NOLINT - no explicit
@@ -165,7 +165,7 @@
template <typename T>
struct StatusOrHelper::Specialize {
- // For non-pointer T, a reference can never be NULL.
+ // For non-pointer T, a reference can never be nullptr.
static inline bool IsValueNull(const T& t) { return false; }
};
config("private_join_and_compute_config") {
include_dirs = [
"//third_party/boringssl/src/include",
]
}
source_set("ec_commutative_cipher") {
sources = [
"chromium_patch.h",
"crypto/big_num.cc",
"crypto/big_num.h",
"crypto/context.cc",
"crypto/context.h",
"crypto/ec_commutative_cipher.cc",
"crypto/ec_commutative_cipher.h",
"crypto/ec_group.cc",
"crypto/ec_group.h",
"crypto/ec_point.cc",
"crypto/ec_point.h",
"crypto/openssl.inc",
"util/canonical_errors.cc",
"util/canonical_errors.h",
"util/status.cc",
"util/status.h",
"util/status.inc",
"util/status_builder.h",
"util/status_macros.h",
"util/statusor.cc",
"util/statusor.h",
]
deps = [
"//base",
"//third_party/boringssl",
]
configs += [ "//build/config/compiler:no_chromium_code" ]
public_configs = [ ":private_join_and_compute_config" ]
}
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
## Community Guidelines
This project follows
[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
specific_include_rules = {
"chromium_patch.h": [
"+base",
]
}
This diff is collapsed.
jdoerrie@chromium.org
vasilii@chromium.org
# COMPONENT: UI>Browser>Passwords
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/compiler_specific.h"
#include "base/logging.h"
#ifndef THIRD_PARTY_PRIVATE_JOIN_AND_COMPUTE_CHROMIUM_PATCH_H_
#define THIRD_PARTY_PRIVATE_JOIN_AND_COMPUTE_CHROMIUM_PATCH_H_
namespace chromium_patch {
// Replacement for glog macro.
template <typename T>
inline T CheckNotNull(const char* names, T&& t) {
CHECK(t) << names;
return std::forward<T>(t);
}
} // namespace chromium_patch
#define CHECK_NOTNULL(val) \
::chromium_patch::CheckNotNull("'" #val "' Must be non nullptr", (val))
#endif // THIRD_PARTY_PRIVATE_JOIN_AND_COMPUTE_CHROMIUM_PATCH_H_
This diff is collapsed.
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/crypto/big_num.h"
#include <cmath>
#include <vector>
#include "third_party/private-join-and-compute/src/chromium_patch.h"
#include "third_party/private-join-and-compute/src/crypto/context.h"
#include "third_party/private-join-and-compute/src/crypto/openssl.inc"
#include "third_party/private-join-and-compute/src/util/status.inc"
namespace private_join_and_compute {
BigNum::BigNum(const BigNum& other)
: bn_(BignumPtr(CHECK_NOTNULL(BN_dup(other.bn_.get())))),
bn_ctx_(other.bn_ctx_) {}
BigNum& BigNum::operator=(const BigNum& other) {
bn_ = BignumPtr(CHECK_NOTNULL(BN_dup(other.bn_.get())));
bn_ctx_ = other.bn_ctx_;
return *this;
}
BigNum::BigNum(BigNum&& other)
: bn_(std::move(other.bn_)), bn_ctx_(other.bn_ctx_) {}
BigNum& BigNum::operator=(BigNum&& other) {
bn_ = std::move(other.bn_);
bn_ctx_ = other.bn_ctx_;
return *this;
}
BigNum::BigNum(BN_CTX* bn_ctx, uint64_t number) : BigNum::BigNum(bn_ctx) {
CRYPTO_CHECK(BN_set_u64(bn_.get(), number));
}
BigNum::BigNum(BN_CTX* bn_ctx, const std::string& bytes)
: BigNum::BigNum(bn_ctx) {
CRYPTO_CHECK(nullptr !=
BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.data()),
bytes.size(), bn_.get()));
}
BigNum::BigNum(BN_CTX* bn_ctx, const unsigned char* bytes, int length)
: BigNum::BigNum(bn_ctx) {
CRYPTO_CHECK(nullptr != BN_bin2bn(bytes, length, bn_.get()));
}
BigNum::BigNum(BN_CTX* bn_ctx) {
bn_ = BignumPtr(CHECK_NOTNULL(BN_new()));
bn_ctx_ = bn_ctx;
}
BigNum::BigNum(BN_CTX* bn_ctx, BignumPtr bn) {
bn_ = std::move(bn);
bn_ctx_ = bn_ctx;
}
const BIGNUM* BigNum::GetConstBignumPtr() const { return bn_.get(); }
std::string BigNum::ToBytes() const {
CHECK(IsNonNegative()) << "Cannot serialize a negative BigNum.";
int length = BN_num_bytes(bn_.get());
std::vector<unsigned char> bytes(length);
BN_bn2bin(bn_.get(), bytes.data());
return std::string(reinterpret_cast<char*>(bytes.data()), bytes.size());
}
StatusOr<uint64_t> BigNum::ToIntValue() const {
uint64_t val;
if (!BN_get_u64(bn_.get(), &val)) {
return InvalidArgumentError("BigNum has more than 64 bits.");
}
return val;
}
int BigNum::BitLength() const { return BN_num_bits(bn_.get()); }
bool BigNum::IsPrime(double prime_error_probability) const {
int rounds = static_cast<int>(ceil(-log(prime_error_probability) / log(4)));
return (1 == BN_is_prime_ex(bn_.get(), rounds, bn_ctx_, nullptr));
}
bool BigNum::IsSafePrime(double prime_error_probability) const {
return IsPrime(prime_error_probability) &&
((*this - BigNum(bn_ctx_, 1)) / BigNum(bn_ctx_, 2))
.IsPrime(prime_error_probability);
}
bool BigNum::IsZero() const { return BN_is_zero(bn_.get()); }
bool BigNum::IsOne() const { return BN_is_one(bn_.get()); }
bool BigNum::IsNonNegative() const { return !BN_is_negative(bn_.get()); }
BigNum BigNum::GetLastNBits(int n) const {
BigNum r = *this;
// Returns 0 on error (if r is already shorter than n bits), but the return
// value in that case should be the original value so there is no need to have
// error checking here.
BN_mask_bits(r.bn_.get(), n);
return r;
}
bool BigNum::IsBitSet(int n) const { return BN_is_bit_set(bn_.get(), n); }
// Returns a BigNum whose value is (- *this).
// Causes a check failure if the operation fails.
BigNum BigNum::Neg() const {
BigNum r = *this;
BN_set_negative(r.bn_.get(), !BN_is_negative(r.bn_.get()));
return r;
}
BigNum BigNum::Add(const BigNum& val) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_add(r.bn_.get(), bn_.get(), val.bn_.get()));
return r;
}
BigNum BigNum::Mul(const BigNum& val) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_mul(r.bn_.get(), bn_.get(), val.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::Sub(const BigNum& val) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_sub(r.bn_.get(), bn_.get(), val.bn_.get()));
return r;
}
BigNum BigNum::Div(const BigNum& val) const {
BigNum r(bn_ctx_);
BignumPtr rem(CHECK_NOTNULL(BN_new()));
CRYPTO_CHECK(
1 == BN_div(r.bn_.get(), rem.get(), bn_.get(), val.bn_.get(), bn_ctx_));
CHECK(BN_is_zero(rem.get())) << "Use DivAndTruncate() instead of Div() if "
"you want truncated division.";
return r;
}
BigNum BigNum::DivAndTruncate(const BigNum& val) const {
BigNum r(bn_ctx_);
BignumPtr rem(CHECK_NOTNULL(BN_new()));
CRYPTO_CHECK(
1 == BN_div(r.bn_.get(), rem.get(), bn_.get(), val.bn_.get(), bn_ctx_));
return r;
}
int BigNum::CompareTo(const BigNum& val) const {
return BN_cmp(bn_.get(), val.bn_.get());
}
BigNum BigNum::Exp(const BigNum& exponent) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 ==
BN_exp(r.bn_.get(), bn_.get(), exponent.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::Mod(const BigNum& m) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_nnmod(r.bn_.get(), bn_.get(), m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModAdd(const BigNum& val, const BigNum& m) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_mod_add(r.bn_.get(), bn_.get(), val.bn_.get(),
m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModSub(const BigNum& val, const BigNum& m) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_mod_sub(r.bn_.get(), bn_.get(), val.bn_.get(),
m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModMul(const BigNum& val, const BigNum& m) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_mod_mul(r.bn_.get(), bn_.get(), val.bn_.get(),
m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModExp(const BigNum& exponent, const BigNum& m) const {
CHECK(exponent.IsNonNegative()) << "Cannot use a negative exponent in BigNum "
"ModExp.";
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_mod_exp(r.bn_.get(), bn_.get(), exponent.bn_.get(),
m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModSqr(const BigNum& m) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_mod_sqr(r.bn_.get(), bn_.get(), m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModInverse(const BigNum& m) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(nullptr !=
BN_mod_inverse(r.bn_.get(), bn_.get(), m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModSqrt(const BigNum& m) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(nullptr !=
BN_mod_sqrt(r.bn_.get(), bn_.get(), m.bn_.get(), bn_ctx_));
return r;
}
BigNum BigNum::ModNegate(const BigNum& m) const {
if (IsZero()) {
return *this;
}
return m - Mod(m);
}
BigNum BigNum::Lshift(int n) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_lshift(r.bn_.get(), bn_.get(), n));
return r;
}
BigNum BigNum::Rshift(int n) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_rshift(r.bn_.get(), bn_.get(), n));
return r;
}
BigNum BigNum::Gcd(const BigNum& val) const {
BigNum r(bn_ctx_);
CRYPTO_CHECK(1 == BN_gcd(r.bn_.get(), bn_.get(), val.bn_.get(), bn_ctx_));
return r;
}
} // namespace private_join_and_compute
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef CRYPTO_BIG_NUM_H_
#define CRYPTO_BIG_NUM_H_
#include <stdint.h>
#include <memory>
#include <string>
#include "third_party/private-join-and-compute/src/crypto/openssl.inc"
#include "third_party/private-join-and-compute/src/util/status.inc"
namespace private_join_and_compute {
// Immutable wrapper class for openssl BIGNUM numbers.
// Used for arithmetic operations on big numbers.
// Makes use of a BN_CTX structure that holds temporary BIGNUMs needed for
// arithmetic operations as dynamic memory allocation to create BIGNUMs is
// expensive.
class BigNum {
public:
// Deletes a BIGNUM.
class BnDeleter {
public:
void operator()(BIGNUM* bn) { BN_clear_free(bn); }
};
// Copies the given BigNum.
BigNum(const BigNum& other);
BigNum& operator=(const BigNum& other);
// Moves the given BigNum.
BigNum(BigNum&& other);
BigNum& operator=(BigNum&& other);
typedef std::unique_ptr<BIGNUM, BnDeleter> BignumPtr;
// Returns the absolute value of this in big-endian form.
std::string ToBytes() const;
// Converts this BigNum to a uint64_t value. Returns an INVALID_ARGUMENT
// error code if the value of *this is larger than 64 bits.
StatusOr<uint64_t> ToIntValue() const;
// Returns the bit length of this BigNum.
int BitLength() const;
// Returns False if the number is composite, True if it is prime with an
// error probability of 1e-40, which gives at least 128 bit security.
bool IsPrime(double prime_error_probability = 1e-40) const;
// Returns False if the number is composite, True if it is safe prime with an
// error probability of at most 1e-40.
bool IsSafePrime(double prime_error_probability = 1e-40) const;
// Return True if this BigNum is zero.
bool IsZero() const;
// Return True if this BigNum is one.
bool IsOne() const;
// Returns True if this BigNum is not negative.
bool IsNonNegative() const;
// Returns a BigNum that is equal to the last n bits of this BigNum.
BigNum GetLastNBits(int n) const;
// Returns true if n-th bit of this big_num is set, false otherwise.
bool IsBitSet(int n) const;
// Returns a BigNum whose value is (- *this).
// Causes a check failure if the operation fails.
BigNum Neg() const;
// Returns a BigNum whose value is (*this + val).
// Causes a check failure if the operation fails.
BigNum Add(const BigNum& val) const;
// Returns a BigNum whose value is (*this * val).
// Causes a check failure if the operation fails.
BigNum Mul(const BigNum& val) const;
// Returns a BigNum whose value is (*this - val).
// Causes a check failure if the operation fails.
BigNum Sub(const BigNum& val) const;
// Returns a BigNum whose value is (*this / val).
// Causes a check failure if the remainder != 0 or if the operation fails.
BigNum Div(const BigNum& val) const;
// Returns a BigNum whose value is *this / val, rounding towards zero.
// Causes a check failure if the remainder != 0 or if the operation fails.
BigNum DivAndTruncate(const BigNum& val) const;
// Compares this BigNum with the specified BigNum.
// Returns -1 if *this < val, 0 if *this == val and 1 if *this > val.
int CompareTo(const BigNum& val) const;
// Returns a BigNum whose value is (*this ^ exponent).
// Causes a check failure if the operation fails.
BigNum Exp(const BigNum& exponent) const;
// Returns a BigNum whose value is (*this mod m).
BigNum Mod(const BigNum& m) const;
// Returns a BigNum whose value is (*this + val mod m).
// Causes a check failure if the operation fails.
BigNum ModAdd(const BigNum& val, const BigNum& m) const;
// Returns a BigNum whose value is (*this - val mod m).
// Causes a check failure if the operation fails.
BigNum ModSub(const BigNum& val, const BigNum& m) const;
// Returns a BigNum whose value is (*this * val mod m).
// For efficiency, please use Montgomery multiplication module if this is done
// multiple times with the same modulus.
// Causes a check failure if the operation fails.
BigNum ModMul(const BigNum& val, const BigNum& m) const;
// Returns a BigNum whose value is (*this ^ exponent mod m).
// Causes a check failure if the operation fails.
BigNum ModExp(const BigNum& exponent, const BigNum& m) const;
// Return a BigNum whose value is (*this ^ 2 mod m).
// Causes a check failure if the operation fails.
BigNum ModSqr(const BigNum& m) const;
// Returns a BigNum whose value is (*this ^ -1 mod m).
// Causes a check failure if the operation fails.
BigNum ModInverse(const BigNum& m) const;
// Returns r such that r ^ 2 == *this mod p.
// Causes a check failure if the operation fails.
BigNum ModSqrt(const BigNum& m) const;
// Computes -a mod m.
// Causes a check failure if the operation fails.
BigNum ModNegate(const BigNum& m) const;
// Returns a BigNum whose value is (*this >> n).
BigNum Rshift(int n) const;
// Returns a BigNum whose value is (*this << n).
// Causes a check failure if the operation fails.
BigNum Lshift(int n) const;
// Computes the greatest common divisor of *this and val.
// Causes a check failure if the operation fails.
BigNum Gcd(const BigNum& val) const;
// Returns a pointer to const BIGNUM to be used with openssl functions.
const BIGNUM* GetConstBignumPtr() const;
private:
// Creates a new BigNum object from a bytes string.
explicit BigNum(BN_CTX* bn_ctx, const std::string& bytes);
// Creates a new BigNum object from a char array.
explicit BigNum(BN_CTX* bn_ctx, const unsigned char* bytes, int length);
// Creates a new BigNum object from the number.
explicit BigNum(BN_CTX* bn_ctx, uint64_t number);
// Creates a new BigNum object with no defined value.
explicit BigNum(BN_CTX* bn_ctx);
// Creates a new BigNum object from the given BIGNUM value.
explicit BigNum(BN_CTX* bn_ctx, BignumPtr bn);
BignumPtr bn_;
BN_CTX* bn_ctx_;
// Context is a factory for BigNum objects.
friend class Context;
};
inline BigNum operator-(const BigNum& a) { return a.Neg(); }
inline BigNum operator+(const BigNum& a, const BigNum& b) { return a.Add(b); }
inline BigNum operator*(const BigNum& a, const BigNum& b) { return a.Mul(b); }
inline BigNum operator-(const BigNum& a, const BigNum& b) { return a.Sub(b); }
// Returns a BigNum whose value is (a / b).
// Causes a check failure if the remainder != 0.
inline BigNum operator/(const BigNum& a, const BigNum& b) { return a.Div(b); }
inline BigNum& operator+=(BigNum& a, const BigNum& b) { return a = a + b; }
inline BigNum& operator*=(BigNum& a, const BigNum& b) { return a = a * b; }
inline BigNum& operator-=(BigNum& a, const BigNum& b) { return a = a - b; }
inline BigNum& operator/=(BigNum& a, const BigNum& b) { return a = a / b; }
inline bool operator==(const BigNum& a, const BigNum& b) {
return 0 == a.CompareTo(b);
}
inline bool operator!=(const BigNum& a, const BigNum& b) { return !(a == b); }
inline bool operator<(const BigNum& a, const BigNum& b) {
return -1 == a.CompareTo(b);
}
inline bool operator>(const BigNum& a, const BigNum& b) {
return 1 == a.CompareTo(b);
}
inline bool operator<=(const BigNum& a, const BigNum& b) {
return a.CompareTo(b) <= 0;
}
inline bool operator>=(const BigNum& a, const BigNum& b) {
return a.CompareTo(b) >= 0;
}
inline BigNum operator%(const BigNum& a, const BigNum& m) { return a.Mod(m); }
inline BigNum operator>>(const BigNum& a, int n) { return a.Rshift(n); }
inline BigNum operator<<(const BigNum& a, int n) { return a.Lshift(n); }
inline BigNum& operator%=(BigNum& a, const BigNum& b) { return a = a % b; }
inline BigNum& operator>>=(BigNum& a, int n) { return a = a >> n; }
inline BigNum& operator<<=(BigNum& a, int n) { return a = a << n; }
} // namespace private_join_and_compute
#endif // CRYPTO_BIG_NUM_H_
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/crypto/context.h"
#include <math.h>
#include <algorithm>
#include <cmath>
#include "third_party/private-join-and-compute/src/chromium_patch.h"
namespace private_join_and_compute {
std::string OpenSSLErrorString() {
char buf[256];
ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
return buf;
}
Context::Context()
: bn_ctx_(CHECK_NOTNULL(BN_CTX_new())),
evp_md_ctx_(CHECK_NOTNULL(EVP_MD_CTX_create())),
zero_bn_(CreateBigNum(0)),
one_bn_(CreateBigNum(1)),
two_bn_(CreateBigNum(2)),
three_bn_(CreateBigNum(3)) {
CHECK(RAND_status()) << "OpenSSL PRNG is not properly seeded.";
HMAC_CTX_init(&hmac_ctx_);
}
Context::~Context() { HMAC_CTX_cleanup(&hmac_ctx_); }
BN_CTX* Context::GetBnCtx() { return bn_ctx_.get(); }
BigNum Context::CreateBigNum(const std::string& bytes) {
return BigNum(bn_ctx_.get(), bytes);
}
BigNum Context::CreateBigNum(uint64_t number) {
return BigNum(bn_ctx_.get(), number);
}
BigNum Context::CreateBigNum(BigNum::BignumPtr bn) {
return BigNum(bn_ctx_.get(), std::move(bn));
}
std::string Context::Sha256String(const std::string& bytes) {
unsigned char hash[EVP_MAX_MD_SIZE];
CRYPTO_CHECK(1 ==
EVP_DigestInit_ex(evp_md_ctx_.get(), EVP_sha256(), nullptr));
CRYPTO_CHECK(
1 == EVP_DigestUpdate(evp_md_ctx_.get(), bytes.c_str(), bytes.length()));
unsigned int md_len;
CRYPTO_CHECK(1 == EVP_DigestFinal_ex(evp_md_ctx_.get(), hash, &md_len));
return std::string(reinterpret_cast<char*>(hash), md_len);
}
std::string Context::Sha512String(const std::string& bytes) {
unsigned char hash[EVP_MAX_MD_SIZE];
CRYPTO_CHECK(1 ==
EVP_DigestInit_ex(evp_md_ctx_.get(), EVP_sha512(), nullptr));
CRYPTO_CHECK(
1 == EVP_DigestUpdate(evp_md_ctx_.get(), bytes.c_str(), bytes.length()));
unsigned int md_len;
CRYPTO_CHECK(1 == EVP_DigestFinal_ex(evp_md_ctx_.get(), hash, &md_len));
return std::string(reinterpret_cast<char*>(hash), md_len);
}
BigNum Context::RandomOracle(const std::string& x, const BigNum& max_value,
RandomOracleHashType hash_type) {
int hash_output_length = 256;
if (hash_type == SHA512) {
hash_output_length = 512;
}
int output_bit_length = max_value.BitLength() + hash_output_length;
int iter_count =
std::ceil(static_cast<float>(output_bit_length) / hash_output_length);
CHECK(iter_count * hash_output_length < 130048)
<< "The domain bit length must not be greater than "
"130048. Desired bit length: "
<< output_bit_length;
int excess_bit_count = (iter_count * hash_output_length) - output_bit_length;
BigNum hash_output = CreateBigNum(0);
for (int i = 1; i < iter_count + 1; i++) {
hash_output = hash_output.Lshift(hash_output_length);
std::string hashed_string;
if (hash_type == SHA512) {
hashed_string = Sha512String(CreateBigNum(i).ToBytes().append(x));
} else {
hashed_string = Sha256String(CreateBigNum(i).ToBytes().append(x));
}
hash_output = hash_output + CreateBigNum(hashed_string);
}
return hash_output.Rshift(excess_bit_count).Mod(max_value);
}
BigNum Context::RandomOracleSha512(const std::string& x,
const BigNum& max_value) {
return RandomOracle(x, max_value, SHA512);
}
BigNum Context::RandomOracleSha256(const std::string& x,
const BigNum& max_value) {
return RandomOracle(x, max_value, SHA256);
}
BigNum Context::PRF(const std::string& key, const std::string& data,
const BigNum& max_value) {
CHECK_GE(key.size() * 8, 80u);
CHECK_LE(max_value.BitLength(), 512)
<< "The requested output length is not supported. The maximum "
"supported output length is 512. The requested output length is "
<< max_value.BitLength();
CRYPTO_CHECK(1 == HMAC_Init_ex(&hmac_ctx_, key.c_str(), key.size(),
EVP_sha512(), nullptr));
CRYPTO_CHECK(1 ==
HMAC_Update(&hmac_ctx_,
reinterpret_cast<const unsigned char*>(data.data()),
data.size()));
unsigned int md_len;
unsigned char hash[EVP_MAX_MD_SIZE];
CRYPTO_CHECK(1 == HMAC_Final(&hmac_ctx_, hash, &md_len));
BigNum hash_bn(bn_ctx_.get(), hash, md_len);
BigNum hash_bn_reduced = hash_bn.GetLastNBits(max_value.BitLength());
if (hash_bn_reduced < max_value) {
return hash_bn_reduced;
} else {
return Context::PRF(key, hash_bn.ToBytes(), max_value);
}
}
BigNum Context::GenerateSafePrime(int prime_length) {
BigNum r(bn_ctx_.get());
CRYPTO_CHECK(1 == BN_generate_prime_ex(r.bn_.get(), prime_length, 1, nullptr,
nullptr, nullptr));
return r;
}
BigNum Context::GeneratePrime(int prime_length) {
BigNum r(bn_ctx_.get());
CRYPTO_CHECK(1 == BN_generate_prime_ex(r.bn_.get(), prime_length, 0, nullptr,
nullptr, nullptr));
return r;
}
BigNum Context::GenerateRandLessThan(const BigNum& max_value) {
BigNum r(bn_ctx_.get());
CRYPTO_CHECK(1 == BN_rand_range(r.bn_.get(), max_value.bn_.get()));
return r;
}
BigNum Context::GenerateRandBetween(const BigNum& start, const BigNum& end) {
CHECK(start < end);
return GenerateRandLessThan(end - start) + start;
}
std::string Context::GenerateRandomBytes(int num_bytes) {
CHECK_GE(num_bytes, 0) << "num_bytes must be nonnegative, provided value was "
<< num_bytes << ".";
std::unique_ptr<unsigned char[]> bytes(new unsigned char[num_bytes]);
CRYPTO_CHECK(1 == RAND_bytes(bytes.get(), num_bytes));
return std::string(reinterpret_cast<char*>(bytes.get()), num_bytes);
}
BigNum Context::RelativelyPrimeRandomLessThan(const BigNum& num) {
BigNum rand_num = GenerateRandLessThan(num);
while (rand_num.Gcd(num) > One()) {
rand_num = GenerateRandLessThan(num);
}
return rand_num;
}
} // namespace private_join_and_compute
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef CRYPTO_CONTEXT_H_
#define CRYPTO_CONTEXT_H_
#include <stdint.h>
#include <memory>
#include <string>
#include "third_party/private-join-and-compute/src/chromium_patch.h"
#include "third_party/private-join-and-compute/src/crypto/big_num.h"
#include "third_party/private-join-and-compute/src/crypto/openssl.inc"
#define CRYPTO_CHECK(expr) CHECK(expr) << OpenSSLErrorString();
namespace private_join_and_compute {
std::string OpenSSLErrorString();
// Wrapper around various contexts needed for openssl operations. It holds a
// BN_CTX to be reused when doing BigNum arithmetic operations and an EVP_MD_CTX
// to be reused when doing hashing operations.
//
// This class provides factory methods for creating BigNum objects that take
// advantage of the BN_CTX structure for arithmetic operations.
//
// This class is not thread-safe, so each thread needs to have a unique Context
// initialized.
class Context {
public:
// Deletes a BN_CTX.
class BnCtxDeleter {
public:
void operator()(BN_CTX* ctx) { BN_CTX_free(ctx); }
};
typedef std::unique_ptr<BN_CTX, BnCtxDeleter> BnCtxPtr;
// Deletes an EVP_MD_CTX.
class EvpMdCtxDeleter {
public:
void operator()(EVP_MD_CTX* ctx) { EVP_MD_CTX_destroy(ctx); }
};
typedef std::unique_ptr<EVP_MD_CTX, EvpMdCtxDeleter> EvpMdCtxPtr;
Context();
// Context is neither copyable nor movable.
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
virtual ~Context();
// Returns a pointer to the openssl BN_CTX that can be reused for arithmetic
// operations.
BN_CTX* GetBnCtx();
// Creates a BigNum initialized with the given BIGNUM value.
BigNum CreateBigNum(BigNum::BignumPtr bn);
// Creates a BigNum initialized with the given bytes string.
BigNum CreateBigNum(const std::string& bytes);
// Creates a BigNum initialized with the given number.
BigNum CreateBigNum(uint64_t number);
// Hashes a string using SHA-256 to a byte string.
virtual std::string Sha256String(const std::string& bytes);
// Hashes a string using SHA-512 to a byte string.
virtual std::string Sha512String(const std::string& bytes);
// A random oracle function mapping x deterministically into a large domain.
//
// The random oracle is similar to the example given in the last paragraph of
// Chapter 6 of [1] where the output is expanded by successively hashing the
// concatenation of the input with a fixed sized counter starting from 1.
//
// [1] Bellare, Mihir, and Phillip Rogaway. "Random oracles are practical:
// A paradigm for designing efficient protocols." Proceedings of the 1st ACM
// conference on Computer and communications security. ACM, 1993.
//
// Returns a long value from the set [0, max_value).
//
// Check Error: if bit length of max_value is greater than 130048.
// Since the counter used for expanding the output is expanded to 8 bit length
// (hard-coded), any counter value that is greater than 256 would cause
// variable length inputs passed to the underlying sha256/sha512 calls and
// might make this random oracle's output not uniform across the output
// domain.
//
// The output length is increased by a security value of 256/512 which reduces
// the bias of selecting certain values more often than others when max_value
// is not a multiple of 2.
virtual BigNum RandomOracleSha256(const std::string& x,
const BigNum& max_value);
virtual BigNum RandomOracleSha512(const std::string& x,
const BigNum& max_value);
// Evaluates a PRF keyed by 'key' on the given data. The returned value is
// less than max_value.
//
// The maximum supported output length is 512. Causes a check failure if the
// bit length of max_value is > 512.
//
// Security:
// The security of this function is given by the length of the key. The key
// should be at least 80 bits long which gives 80 bit security. Fails if the
// key is less than 80 bits.
//
// This function is susceptible to timing attacks.
BigNum PRF(const std::string& key, const std::string& data,
const BigNum& max_value);
// Creates a safe prime BigNum with the given bit-length.
BigNum GenerateSafePrime(int prime_length);
// Creates a prime BigNum with the given bit-length.
//
// Note: In many cases, we need to use a safe prime for cryptographic security
// to hold. In this case, we should use GenerateSafePrime.
BigNum GeneratePrime(int prime_length);
// Generates a cryptographically strong pseudo-random in the range [0,
// max_value).
// Marked virtual for tests.
virtual BigNum GenerateRandLessThan(const BigNum& max_value);
// Generates a cryptographically strong pseudo-random in the range [start,
// end).
// Marked virtual for tests.
virtual BigNum GenerateRandBetween(const BigNum& start, const BigNum& end);
// Generates a cryptographically strong pseudo-random bytes of the specified
// length.
// Marked virtual for tests.
virtual std::string GenerateRandomBytes(int num_bytes);
// Returns a BigNum that is relatively prime to the num and less than the num.
virtual BigNum RelativelyPrimeRandomLessThan(const BigNum& num);
inline const BigNum& Zero() const { return zero_bn_; }
inline const BigNum& One() const { return one_bn_; }
inline const BigNum& Two() const { return two_bn_; }
inline const BigNum& Three() const { return three_bn_; }
private:
BnCtxPtr bn_ctx_;
EvpMdCtxPtr evp_md_ctx_;
HMAC_CTX hmac_ctx_;
const BigNum zero_bn_;
const BigNum one_bn_;
const BigNum two_bn_;
const BigNum three_bn_;
enum RandomOracleHashType {
SHA256,
SHA512,
};
// If hash_type is invalid, this function will default to using SHA256.
virtual BigNum RandomOracle(const std::string& x, const BigNum& max_value,
RandomOracleHashType hash_type);
};
} // namespace private_join_and_compute
#endif // CRYPTO_CONTEXT_H_
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/crypto/ec_commutative_cipher.h"
#include <utility>
#include "third_party/private-join-and-compute/src/util/status.inc"
namespace private_join_and_compute {
ECCommutativeCipher::ECCommutativeCipher(std::unique_ptr<Context> context,
ECGroup group, BigNum private_key,
HashType hash_type)
: context_(std::move(context)),
group_(std::move(group)),
private_key_(std::move(private_key)),
private_key_inverse_(private_key_.ModInverse(group_.GetOrder())),
hash_type_(hash_type) {}
bool ECCommutativeCipher::ValidateHashType(HashType hash_type) {
return (hash_type == SHA256 || hash_type == SHA512);
}
StatusOr<std::unique_ptr<ECCommutativeCipher>>
ECCommutativeCipher::CreateWithNewKey(int curve_id, HashType hash_type) {
std::unique_ptr<Context> context(new Context);
ASSIGN_OR_RETURN(ECGroup group, ECGroup::Create(curve_id, context.get()));
if (!ECCommutativeCipher::ValidateHashType(hash_type)) {
return InvalidArgumentError("Invalid hash type.");
}
BigNum private_key = group.GeneratePrivateKey();
return std::unique_ptr<ECCommutativeCipher>(new ECCommutativeCipher(
std::move(context), std::move(group), std::move(private_key), hash_type));
}
StatusOr<std::unique_ptr<ECCommutativeCipher>>
ECCommutativeCipher::CreateFromKey(int curve_id, const std::string& key_bytes,
HashType hash_type) {
std::unique_ptr<Context> context(new Context);
ASSIGN_OR_RETURN(ECGroup group, ECGroup::Create(curve_id, context.get()));
if (!ECCommutativeCipher::ValidateHashType(hash_type)) {
return InvalidArgumentError("Invalid hash type.");
}
BigNum private_key = context->CreateBigNum(key_bytes);
auto status = group.CheckPrivateKey(private_key);
if (!status.ok()) {
return status;
}
return std::unique_ptr<ECCommutativeCipher>(new ECCommutativeCipher(
std::move(context), std::move(group), std::move(private_key), hash_type));
}
StatusOr<std::string> ECCommutativeCipher::Encrypt(
const std::string& plaintext) const {
StatusOr<ECPoint> status_or_point;
if (hash_type_ == SHA512) {
status_or_point = group_.GetPointByHashingToCurveSha512(plaintext);
} else if (hash_type_ == SHA256) {
status_or_point = group_.GetPointByHashingToCurveSha256(plaintext);
} else {
return InvalidArgumentError("Invalid hash type.");
}
if (!status_or_point.ok()) {
return status_or_point.status();
}
ASSIGN_OR_RETURN(ECPoint encrypted_point,
Encrypt(status_or_point.ValueOrDie()));
return encrypted_point.ToBytesCompressed();
}
StatusOr<std::string> ECCommutativeCipher::ReEncrypt(
const std::string& ciphertext) const {
ASSIGN_OR_RETURN(ECPoint point, group_.CreateECPoint(ciphertext));
ASSIGN_OR_RETURN(ECPoint reencrypted_point, Encrypt(point));
return reencrypted_point.ToBytesCompressed();
}
StatusOr<ECPoint> ECCommutativeCipher::Encrypt(const ECPoint& point) const {
return point.Mul(private_key_);
}
StatusOr<std::string> ECCommutativeCipher::Decrypt(
const std::string& ciphertext) const {
ASSIGN_OR_RETURN(ECPoint point, group_.CreateECPoint(ciphertext));
ASSIGN_OR_RETURN(ECPoint decrypted_point, point.Mul(private_key_inverse_));
return decrypted_point.ToBytesCompressed();
}
std::string ECCommutativeCipher::GetPrivateKeyBytes() const {
return private_key_.ToBytes();
}
} // namespace private_join_and_compute
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef EC_COMMUTATIVE_CIPHER_H_
#define EC_COMMUTATIVE_CIPHER_H_
#include <memory>
#include <string>
#include "third_party/private-join-and-compute/src/crypto/big_num.h"
#include "third_party/private-join-and-compute/src/crypto/context.h"
#include "third_party/private-join-and-compute/src/crypto/ec_group.h"
#include "third_party/private-join-and-compute/src/crypto/ec_point.h"
#include "third_party/private-join-and-compute/src/util/status.inc"
namespace private_join_and_compute {
// ECCommutativeCipher class with the property that K1(K2(a)) = K2(K1(a))
// where K(a) is encryption with the key K. https://eprint.iacr.org/2008/356.pdf
//
// This class allows two parties to determine if they share the same value,
// without revealing the sensitive value to each other.
//
// This class also allows homomorphically re-encrypting an ElGamal ciphertext
// with an EC cipher key K. If the original ciphertext was an encryption of m,
// then the re-encrypted ciphertext is effectively an encryption of K(m). This
// re-encryption does not re-randomize the ciphertext, and so is only secure
// when the underlying messages "m" are pseudorandom.
//
// The encryption is performed over an elliptic curve.
//
// This class is not thread-safe.
//
// Security: The provided bit security is half the number of bits of the
// underlying curve. For example, using curve NID_secp224r1 gives 112 bit
// security.
//
// Example: To generate a cipher with a new private key for the named curve
// NID_secp224r1. The key can be securely stored and reused.
// #include <openssl/obj_mac.h>
// std::unique_ptr<ECCommutativeCipher> cipher =
// ECCommutativeCipher::CreateWithNewKey(
// NID_secp224r1, ECCommutativeCipher::HashType::SHA256);
// string key_bytes = cipher->GetPrivateKeyBytes();
//
// Example: To generate a cipher with an existing private key for the named
// curve NID_secp224r1.
// #include <openssl/obj_mac.h>
// std::unique_ptr<ECCommutativeCipher> cipher =
// ECCommutativeCipher::CreateFromKey(
// NID_secp224r1, key_bytes, ECCommutativeCipher::HashType::SHA256);
//
// Example: To encrypt a message using a std::unique_ptr<ECCommutativeCipher>
// cipher generated as above.
// string encrypted_string = cipher->Encrypt("secret");
//
// Example: To re-encrypt a message already encrypted by another party using a
// std::unique_ptr<ECCommutativeCipher> cipher generated as above.
// ::private_join_and_compute::StatusOr<string> double_encrypted_string =
// cipher->ReEncrypt(encrypted_string);
//
// Example: To decrypt a message that has already been encrypted by the same
// party using a std::unique_ptr<ECCommutativeCipher> cipher generated as
// above.
// ::private_join_and_compute::StatusOr<string> decrypted_string =
// cipher->Decrypt(encrypted_string);
//
// Example: To re-encrypt a message that has already been encrypted using a
// std::unique_ptr<CommutativeElGamal> ElGamal key:
// ::private_join_and_compute::StatusOr<std::pair<string, string>> double_encrypted_string =
// cipher->ReEncryptElGamalCiphertext(elgamal_ciphertext);
class ECCommutativeCipher {
public:
// The hash function used by the ECCommutativeCipher.
enum HashType {
SHA256,
SHA512,
};
// Check for valid HashType.
static bool ValidateHashType(HashType hash_type);
// ECCommutativeCipher is neither copyable nor assignable.
ECCommutativeCipher(const ECCommutativeCipher&) = delete;
ECCommutativeCipher& operator=(const ECCommutativeCipher&) = delete;
// Creates an ECCommutativeCipher object with a new random private key.
// Use this method when the key is created for the first time or it needs to
// be refreshed.
// Returns INVALID_ARGUMENT status instead if the curve_id is not valid
// or INTERNAL status when crypto operations are not successful.
static ::private_join_and_compute::StatusOr<std::unique_ptr<ECCommutativeCipher>>
CreateWithNewKey(int curve_id, HashType hash_type);
// Creates an ECCommutativeCipher object with the given private key.
// A new key should be created for each session and all values should be
// unique in one session because the encryption is deterministic.
// Use this when the key is stored securely to be used at different steps of
// the protocol in the same session or by multiple processes.
// Returns INVALID_ARGUMENT status instead if the private_key is not valid for
// the given curve or the curve_id is not valid.
// Returns INTERNAL status when crypto operations are not successful.
static ::private_join_and_compute::StatusOr<std::unique_ptr<ECCommutativeCipher>>
CreateFromKey(int curve_id, const std::string& key_bytes, HashType hash_type);
// Encrypts a string with the private key to a point on the elliptic curve.
//
// To encrypt, the string is hashed to a point on the curve which is then
// multiplied with the private key.
//
// The resulting point is returned encoded in compressed form as defined in
// ANSI X9.62 ECDSA.
//
// Returns an INVALID_ARGUMENT error code if an error occurs.
::private_join_and_compute::StatusOr<std::string> Encrypt(const std::string& plaintext) const;
// Encrypts an encoded point with the private key.
//
// Returns an INVALID_ARGUMENT error code if the input is not a valid encoding
// of a point on this curve as defined in ANSI X9.62 ECDSA.
//
// The result is a point encoded in compressed form.
//
// This method can also be used to encrypt a value that has already been
// hashed to the curve.
::private_join_and_compute::StatusOr<std::string> ReEncrypt(
const std::string& ciphertext) const;
// Decrypts an encoded point with the private key.
//
// Returns an INVALID_ARGUMENT error code if the input is not a valid encoding
// of a point on this curve as defined in ANSI X9.62 ECDSA.
//
// The result is a point encoded in compressed form.
//
// If the input point was double-encrypted, once with this key and once with
// another key, then the result point is single-encrypted with the other key.
//
// If the input point was single encrypted with this key, then the result
// point is the original, unencrypted point. Note that this will not reverse
// hashing to the curve.
::private_join_and_compute::StatusOr<std::string> Decrypt(
const std::string& ciphertext) const;
// Returns the private key bytes so the key can be stored and reused.
std::string GetPrivateKeyBytes() const;
private:
// Creates a new ECCommutativeCipher object with the given private key for
// the given EC group.
ECCommutativeCipher(std::unique_ptr<Context> context, ECGroup group,
BigNum private_key, HashType hash_type);
// Encrypts a point by multiplying the point with the private key.
::private_join_and_compute::StatusOr<ECPoint> Encrypt(const ECPoint& point) const;
// Context used for storing temporary values to be reused across openssl
// function calls for better performance.
std::unique_ptr<Context> context_;
// The EC Group representing the curve definition.
const ECGroup group_;
// The private key used for encryption.
const BigNum private_key_;
// The private key inverse, used for decryption.
const BigNum private_key_inverse_;
// The hash function used by the cipher.
const HashType hash_type_;
};
} // namespace private_join_and_compute
#endif // EC_COMMUTATIVE_CIPHER_H_
This diff is collapsed.
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef CRYPTO_EC_GROUP_H_
#define CRYPTO_EC_GROUP_H_
#include <memory>
#include <string>
#include "third_party/private-join-and-compute/src/crypto/big_num.h"
#include "third_party/private-join-and-compute/src/crypto/context.h"
#include "third_party/private-join-and-compute/src/crypto/openssl.inc"
#include "third_party/private-join-and-compute/src/util/status.inc"
namespace private_join_and_compute {
class ECPoint;
// Wrapper class for openssl EC_GROUP.
class ECGroup {
public:
// Deletes a EC_GROUP.
class ECGroupDeleter {
public:
void operator()(EC_GROUP* group) { EC_GROUP_free(group); }
};
typedef std::unique_ptr<EC_GROUP, ECGroupDeleter> ECGroupPtr;
// Constructs a new ECGroup object for the given named curve id.
// See openssl header obj_mac.h for the available built-in curves.
// Use a well-known prime curve such as NID_secp224r1 recommended by NIST.
// Returns INTERNAL error code if there is a failure in crypto operations.
// Security: this function is secure only for prime order curves.
// (All supported curves in BoringSSL have prime order.)
static StatusOr<ECGroup> Create(int curve_id, Context* context);
// Generates a new private key. The private key is a cryptographically strong
// pseudo-random number in the range (0, order).
BigNum GeneratePrivateKey() const;
// Verifies that the random key is a valid number in the range (0, order).
// Returns Status::OK if the key is valid, otherwise returns INVALID_ARGUMENT.
Status CheckPrivateKey(const BigNum& priv_key) const;
// Hashes m to a point on the elliptic curve y^2 = x^3 + ax + b over a
// prime field using SHA256 with "try-and-increment" method.
// See https://crypto.stanford.edu/~dabo/papers/bfibe.pdf, Section 5.2.
// Returns an INVALID_ARGUMENT error code if an error occurs.
//
// Security: The number of operations required to hash a string depends on the
// string, which could lead to a timing attack.
// Security: This function is only secure for curves of prime order.
StatusOr<ECPoint> GetPointByHashingToCurveSha256(const std::string& m) const;
// Hashes m to a point on the elliptic curve y^2 = x^3 + ax + b over a
// prime field using SHA512.
// Returns an INVALID_ARGUMENT error code if an error occurs.
//
// Security: The number of operations required to hash a string depends on the
// string, which could lead to a timing attack.
StatusOr<ECPoint> GetPointByHashingToCurveSha512(const std::string& m) const;
// Returns y^2 for the given x. The returned value is computed as x^3 + ax + b
// mod p, where a and b are the parameters of the curve.
BigNum ComputeYSquare(const BigNum& x) const;
// Returns a fixed generator for this group.
// Returns an INTERNAL error code if it fails.
StatusOr<ECPoint> GetFixedGenerator() const;
// Returns a random generator for this group.
// Returns an INTERNAL error code if it fails.
StatusOr<ECPoint> GetRandomGenerator() const;
// Creates an ECPoint from the given string.
// Returns an INTERNAL error code if creating the point fails.
// Returns an INVALID_ARGUMENT error code if the created point is not in this
// group or if it is the point at infinity.
StatusOr<ECPoint> CreateECPoint(const std::string& bytes) const;
// The parameters describing an elliptic curve given by the equation
// y^2 = x^3 + a * x + b over a prime field Fp.
struct CurveParams {
BigNum p;
BigNum a;
BigNum b;
};
// Returns the order.
const BigNum& GetOrder() const { return order_; }
// Returns the cofactor.
const BigNum& GetCofactor() const { return cofactor_; }
// Creates an ECPoint which is the identity.
StatusOr<ECPoint> GetPointAtInfinity() const;
private:
ECGroup(Context* context, ECGroupPtr group, BigNum order, BigNum cofactor,
CurveParams curve_params, BigNum p_minus_one_over_two);
// Creates an ECPoint object with the given x, y affine coordinates.
// Returns an INVALID_ARGUMENT error code if the point (x, y) is not in this
// group or if it is the point at infinity.
StatusOr<ECPoint> CreateECPoint(const BigNum& x, const BigNum& y) const;
// Returns true if q is a quadratic residue modulo curve_params_.p_.
bool IsSquare(const BigNum& q) const;
// Checks if the given point is valid. Returns false if the point is not in
// the group or if it is the point is at infinity.
bool IsValid(const ECPoint& point) const;
// Returns true if the given point is in the group.
bool IsOnCurve(const ECPoint& point) const;
// Returns true if the given point is at infinity.
bool IsAtInfinity(const ECPoint& point) const;
Context* context_;
ECGroupPtr group_;
// The order of this group.
BigNum order_;
// The cofactor of this group.
BigNum cofactor_;
// The parameters of the curve. These values are used to hash a number to a
// point on the curve.
CurveParams curve_params_;
// Constant used to evaluate if a number is a quadratic residue.
BigNum p_minus_one_over_two_;
StatusOr<ECPoint> GetPointByHashingToCurveInternal(const BigNum& x) const;
};
} // namespace private_join_and_compute
#endif // CRYPTO_EC_GROUP_H_
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/crypto/ec_point.h"
#include <vector>
#include "third_party/private-join-and-compute/src/chromium_patch.h"
#include "third_party/private-join-and-compute/src/crypto/big_num.h"
#include "third_party/private-join-and-compute/src/crypto/context.h"
#include "third_party/private-join-and-compute/src/crypto/openssl.inc"
#include "third_party/private-join-and-compute/src/util/status.inc"
namespace private_join_and_compute {
ECPoint::ECPoint(const EC_GROUP* group, BN_CTX* bn_ctx)
: bn_ctx_(bn_ctx), group_(group) {
point_ = ECPointPtr(CHECK_NOTNULL(EC_POINT_new(group_)));
}
ECPoint::ECPoint(const EC_GROUP* group, BN_CTX* bn_ctx, const BigNum& x,
const BigNum& y)
: ECPoint::ECPoint(group, bn_ctx) {
CRYPTO_CHECK(1 == EC_POINT_set_affine_coordinates_GFp(
group_, point_.get(), x.GetConstBignumPtr(),
y.GetConstBignumPtr(), bn_ctx_));
}
ECPoint::ECPoint(const EC_GROUP* group, BN_CTX* bn_ctx, ECPointPtr point)
: ECPoint::ECPoint(group, bn_ctx) {
point_ = std::move(point);
}
StatusOr<std::string> ECPoint::ToBytesCompressed() const {
int length = EC_POINT_point2oct(
group_, point_.get(), POINT_CONVERSION_COMPRESSED, nullptr, 0, bn_ctx_);
std::vector<unsigned char> bytes(length);
if (0 == EC_POINT_point2oct(group_, point_.get(), POINT_CONVERSION_COMPRESSED,
bytes.data(), length, bn_ctx_)) {
return InternalError(
"EC_POINT_point2oct failed:" + OpenSSLErrorString());
}
return std::string(reinterpret_cast<char*>(bytes.data()), bytes.size());
}
StatusOr<std::string> ECPoint::ToBytesUnCompressed() const {
int length = EC_POINT_point2oct(
group_, point_.get(), POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, bn_ctx_);
std::vector<unsigned char> bytes(length);
if (0 == EC_POINT_point2oct(group_, point_.get(),
POINT_CONVERSION_UNCOMPRESSED, bytes.data(),
length, bn_ctx_)) {
return InternalError(
"EC_POINT_point2oct failed:" + OpenSSLErrorString());
}
return std::string(reinterpret_cast<char*>(bytes.data()), bytes.size());
}
StatusOr<ECPoint> ECPoint::Mul(const BigNum& scalar) const {
ECPoint r = ECPoint(group_, bn_ctx_);
if (1 != EC_POINT_mul(group_, r.point_.get(), nullptr, point_.get(),
scalar.GetConstBignumPtr(), bn_ctx_)) {
return InternalError(
"EC_POINT_mul failed:" + OpenSSLErrorString());
}
return std::move(r);
}
StatusOr<ECPoint> ECPoint::Add(const ECPoint& point) const {
ECPoint r = ECPoint(group_, bn_ctx_);
if (1 != EC_POINT_add(group_, r.point_.get(), point_.get(),
point.point_.get(), bn_ctx_)) {
return InternalError(
"EC_POINT_add failed:" + OpenSSLErrorString());
}
return std::move(r);
}
StatusOr<ECPoint> ECPoint::Clone() const {
ECPoint r = ECPoint(group_, bn_ctx_);
if (1 != EC_POINT_copy(r.point_.get(), point_.get())) {
return InternalError(
"EC_POINT_copy failed:" + OpenSSLErrorString());
}
return std::move(r);
}
StatusOr<ECPoint> ECPoint::Inverse() const {
// Create a copy of this.
ASSIGN_OR_RETURN(ECPoint inv, Clone());
// Invert the copy in-place.
if (1 != EC_POINT_invert(group_, inv.point_.get(), bn_ctx_)) {
return InternalError(
"EC_POINT_invert failed:" + OpenSSLErrorString());
}
return std::move(inv);
}
bool ECPoint::IsPointAtInfinity() const {
return EC_POINT_is_at_infinity(group_, point_.get());
}
bool ECPoint::CompareTo(const ECPoint& point) const {
return 0 == EC_POINT_cmp(group_, point_.get(), point.point_.get(), bn_ctx_);
}
} // namespace private_join_and_compute
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef CRYPTO_EC_POINT_H_
#define CRYPTO_EC_POINT_H_
#include <memory>
#include <string>
#include "third_party/private-join-and-compute/src/crypto/openssl.inc"
#include "third_party/private-join-and-compute/src/util/status.inc"
namespace private_join_and_compute {
class BigNum;
class ECGroup;
// Wrapper class for openssl EC_POINT.
class ECPoint {
public:
// Deletes an EC_POINT.
class ECPointDeleter {
public:
void operator()(EC_POINT* point) { EC_POINT_clear_free(point); }
};
typedef std::unique_ptr<EC_POINT, ECPointDeleter> ECPointPtr;
// ECPoint is movable.
ECPoint(ECPoint&& that) = default;
ECPoint& operator=(ECPoint&& that) = default;
// ECPoint is not copyable. Use Clone to copy, instead.
explicit ECPoint(const ECPoint& that) = delete;
ECPoint& operator=(const ECPoint& that) = delete;
// Converts this point to octet string in compressed form as defined in ANSI
// X9.62 ECDSA.
StatusOr<std::string> ToBytesCompressed() const;
// Allows faster conversions than ToBytesCompressed but doubles the size of
// the serialized point.
StatusOr<std::string> ToBytesUnCompressed() const;
// Returns an ECPoint whose value is (this * scalar).
// Returns an INTERNAL error code if it fails.
StatusOr<ECPoint> Mul(const BigNum& scalar) const;
// Returns an ECPoint whose value is (this + point).
// Returns an INTERNAL error code if it fails.
StatusOr<ECPoint> Add(const ECPoint& point) const;
// Returns an ECPoint whose value is (- this), the additive inverse of this.
// Returns an INTERNAL error code if it fails.
StatusOr<ECPoint> Inverse() const;
// Returns "true" if the value of this ECPoint is the point-at-infinity.
// (The point-at-infinity is the additive unit in the EC group).
bool IsPointAtInfinity() const;
// Returns true if this equals point, false otherwise.
bool CompareTo(const ECPoint& point) const;
// Returns an ECPoint that is a copy of this.
StatusOr<ECPoint> Clone() const;
private:
// Creates an ECPoint on the given group;
ECPoint(const EC_GROUP* group, BN_CTX* bn_ctx);
// Creates an ECPoint on the given group from the given EC_POINT;
ECPoint(const EC_GROUP* group, BN_CTX* bn_ctx, ECPointPtr point);
// Creates an ECPoint object with the given x, y affine coordinates.
ECPoint(const EC_GROUP* group, BN_CTX* bn_ctx, const BigNum& x,
const BigNum& y);
BN_CTX* bn_ctx_;
const EC_GROUP* group_;
ECPointPtr point_;
// ECGroup is a factory for ECPoint.
friend class ECGroup;
};
inline bool operator==(const ECPoint& a, const ECPoint& b) {
return a.CompareTo(b);
}
inline bool operator!=(const ECPoint& a, const ECPoint& b) { return !(a == b); }
} // namespace private_join_and_compute
#endif // CRYPTO_EC_POINT_H_
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
// Contains all the OpenSSL includes we use.
#include <openssl/aead.h>
#include <openssl/bn.h>
#include <openssl/buffer.h>
#include <openssl/crypto.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/obj_mac.h>
#include <openssl/ossl_typ.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
This diff is collapsed.
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/util/canonical_errors.h"
#include <string>
#include "third_party/private-join-and-compute/src/util/status.h"
namespace private_join_and_compute {
Status InternalError(const std::string& message) {
return Status(private_join_and_compute::StatusCode::kInternal, message);
}
Status InvalidArgumentError(const std::string& message) {
return Status(private_join_and_compute::StatusCode::kInvalidArgument, message);
}
bool IsInternal(const Status& status) {
return status.code() == private_join_and_compute::StatusCode::kInternal;
}
bool IsInvalidArgument(const Status& status) {
return status.code() == private_join_and_compute::StatusCode::kInvalidArgument;
}
} // namespace private_join_and_compute
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef UTIL_CANONICAL_ERRORS_H_
#define UTIL_CANONICAL_ERRORS_H_
#include <string>
#include "third_party/private-join-and-compute/src/util/status.h"
namespace private_join_and_compute {
Status InternalError(const std::string& message);
Status InvalidArgumentError(const std::string& message);
bool IsInternal(const Status& status);
bool IsInvalidArgument(const Status& status);
} // namespace private_join_and_compute
#endif // UTIL_CANONICAL_ERRORS_H_
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/util/status.h"
#include <sstream>
#include <utility>
namespace private_join_and_compute {
Status::Status() : code_(private_join_and_compute::StatusCode::kOk), message_("") {}
Status::Status(private_join_and_compute::StatusCode error, std::string error_message)
: code_(error), message_(std::move(error_message)) {
if (code_ == private_join_and_compute::StatusCode::kOk) {
message_.clear();
}
}
Status::Status(const Status& other)
: code_(other.code_), message_(other.message_) {}
Status& Status::operator=(const Status& other) {
code_ = other.code_;
message_ = other.message_;
return *this;
}
std::string Status::ToString() const {
if (code_ == private_join_and_compute::StatusCode::kOk) {
return "OK";
}
std::ostringstream stringStream;
stringStream << code_ << ": " << message_;
return stringStream.str();
}
Status Annotate(const Status& s, const std::string& msg) {
if (s.ok() || msg.empty()) return s;
std::string new_msg;
if (s.message().empty()) {
new_msg = msg;
} else {
new_msg = s.message() + "; " + msg;
}
return Status(s.code(), new_msg);
}
extern std::ostream& operator<<(std::ostream& os, const Status& other) {
os << other.ToString();
return os;
}
} // namespace private_join_and_compute
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef UTIL_STATUS_H_
#define UTIL_STATUS_H_
#include <string>
namespace private_join_and_compute {
enum StatusCode {
kOk = 0,
kCancelled = 1,
kUnknown = 2,
kInvalidArgument = 3,
kDeadlineExceeded = 4,
kNotFound = 5,
kAlreadyExists = 6,
kPermissionDenied = 7,
kResourceExhausted = 8,
kFailedPrecondition = 9,
kAborted = 10,
kOutOfRange = 11,
kUnimplemented = 12,
kInternal = 13,
kUnavailable = 14,
kDataLoss = 15,
kUnauthenticated = 16,
kDoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_ = 20
};
// A Status is a combination of an error code and a string message (for non-OK
// error codes).
class Status {
public:
// Creates an OK status
Status();
// Make a Status from the specified error and message.
Status(private_join_and_compute::StatusCode error, std::string error_message);
Status(const Status& other);
Status& operator=(const Status& other);
// Some pre-defined Status objects
static Status OK() {
return Status();
}
static Status UNKNOWN() {
return Status(private_join_and_compute::StatusCode::kUnknown, "");
}
// Accessors
bool ok() const { return code_ == private_join_and_compute::StatusCode::kOk; }
int error_code() const { return code_; }
private_join_and_compute::StatusCode code() const { return code_; }
const std::string& message() const { return message_; }
bool operator==(const Status& x) const;
bool operator!=(const Status& x) const;
// NoOp
void IgnoreError() const {}
std::string ToString() const;
private:
private_join_and_compute::StatusCode code_;
std::string message_;
};
inline bool Status::operator==(const Status& other) const {
return (this->code_ == other.code_) && (this->message_ == other.message_);
}
inline bool Status::operator!=(const Status& other) const {
return !(*this == other);
}
// Returns a Status that is identical to 's' except that the error_message()
// has been augmented by adding 'msg' to the end of the original error
// message.
Status Annotate(const Status& s, const std::string& msg);
extern std::ostream& operator<<(std::ostream& os, const Status& other);
inline Status OkStatus() { return Status(); }
} // namespace private_join_and_compute
#endif // UTIL_STATUS_H_
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/util/canonical_errors.h"
#include "third_party/private-join-and-compute/src/util/status.h"
#include "third_party/private-join-and-compute/src/util/statusor.h"
#include "third_party/private-join-and-compute/src/util/status_macros.h"
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
#ifndef UTIL_STATUS_MACROS_H_
#define UTIL_STATUS_MACROS_H_
#include "third_party/private-join-and-compute/src/chromium_patch.h"
#include "third_party/private-join-and-compute/src/util/status.h"
#include "third_party/private-join-and-compute/src/util/statusor.h"
// Helper macro that checks if the right hand side (rexpression) evaluates to a
// StatusOr with Status OK, and if so assigns the value to the value on the left
// hand side (lhs), otherwise returns the error status. Example:
// ASSIGN_OR_RETURN(lhs, rexpression);
#define ASSIGN_OR_RETURN(lhs, rexpr) \
PRIVACY_BLINDERS_ASSIGN_OR_RETURN_IMPL_( \
PRIVACY_BLINDERS_STATUS_MACROS_IMPL_CONCAT_(status_or_value, __LINE__), \
lhs, rexpr)
// Internal helper.
#define PRIVACY_BLINDERS_ASSIGN_OR_RETURN_IMPL_(statusor, lhs, rexpr) \
auto statusor = (rexpr); \
if (UNLIKELY(!statusor.ok())) { \
return std::move(statusor).status(); \
} \
lhs = std::move(statusor).ValueOrDie()
// Internal helper for concatenating macro values.
#define PRIVACY_BLINDERS_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y) x##y
#define PRIVACY_BLINDERS_STATUS_MACROS_IMPL_CONCAT_(x, y) \
PRIVACY_BLINDERS_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y)
#endif // UTIL_STATUS_MACROS_H_
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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 "third_party/private-join-and-compute/src/util/statusor.h"
#include "third_party/private-join-and-compute/src/chromium_patch.h"
#include "third_party/private-join-and-compute/src/util/status.h"
namespace private_join_and_compute {
namespace internal {
static const char* kInvalidStatusCtorArgMessage =
"Status::OK is not a valid constructor argument to StatusOr<T>";
static const char* kNullObjectCtorArgMessage =
"nullptr is not a valid constructor argument to StatusOr<T*>";
Status StatusOrHelper::HandleInvalidStatusCtorArg() {
LOG(DFATAL) << kInvalidStatusCtorArgMessage;
// In optimized builds, we will fall back to private_join_and_compute::StatusCode::kInternal.
return Status(::private_join_and_compute::StatusCode::kInternal,
kInvalidStatusCtorArgMessage);
}
Status StatusOrHelper::HandleNullObjectCtorArg() {
LOG(DFATAL) << kNullObjectCtorArgMessage;
// In optimized builds, we will fall back to
// ::private_join_and_compute::StatusCode::kInternal.
return Status(::private_join_and_compute::StatusCode::kInternal, kNullObjectCtorArgMessage);
}
void StatusOrHelper::Crash(const Status& status) {
LOG(FATAL) << "Attempting to fetch value instead of handling error "
<< status;
}
} // namespace internal
} // namespace private_join_and_compute
/*
* Copyright 2019 Google Inc.
* 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
*
* https://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.
*/
// StatusOr<T> is the union (w/o using Union) of a Status object and a T object.
// StatusOr models the concept of an object that is either a usable value, or an
// error Status explaining why such a value is not present. To this end,
// StatusOr<T> does not allow its Status value to be Status::OK. Furthermore,
// the value of a StatusOr<T*> must not be null. This is enforced by a debug
// check in most cases, but even when it is not, clients must not set the value
// to null.
//
// The primary use-case for StatusOr<T> is as the return value of a function
// which may fail.
//
// Example client usage for a StatusOr<T>, where T is not a pointer:
//
// StatusOr<float> result = DoBigCalculationThatCouldFail();
// if (result.ok()) {
// float answer = result.ValueOrDie();
// printf("Big calculation yielded: %f", answer);
// } else {
// LOG(ERROR) << result.status();
// }
//
// Example client usage for a StatusOr<T*>:
//
// StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
// if (result.ok()) {
// std::unique_ptr<Foo> foo(result.ValueOrDie());
// foo->DoSomethingCool();
// } else {
// LOG(ERROR) << result.status();
// }
//
// Example client usage for a StatusOr<std::unique_ptr<T>>:
//
// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
// if (result.ok()) {
// std::unique_ptr<Foo> foo = std::move(result.ValueOrDie());
// foo->DoSomethingCool();
// } else {
// LOG(ERROR) << result.status();
// }
//
// Example factory implementation returning StatusOr<T*>:
//
// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
// if (arg <= 0) {
// return Status(::private_join_and_compute::StatusCode::kInvalidArgument,
// "Arg must be positive");
// } else {
// return new Foo(arg);
// }
// }
//
#ifndef UTIL_STATUSOR_H_
#define UTIL_STATUSOR_H_
#include <memory>
#include <new>
#include <utility>
#include "third_party/private-join-and-compute/src/util/status.h" // IWYU pragma: export // for Status
namespace private_join_and_compute {
template <typename T>
class StatusOr {
public:
// Construct a new StatusOr with Status::UNKNOWN status
StatusOr();
// Construct a new StatusOr with the given non-ok status. After calling
// this constructor, calls to ValueOrDie() will CHECK-fail.
//
// NOTE: Not explicit - we want to use StatusOr<T> as a return
// value, so it is convenient and sensible to be able to do 'return
// Status()' when the return type is StatusOr<T>.
//
// REQUIRES: status != Status::OK. This requirement is DCHECKed.
// In optimized builds, passing Status::OK here will have the effect
// of passing PosixErrorSpace::EINVAL as a fallback.
StatusOr(const Status& status); // NOLINT - no explicit
// Construct a new StatusOr with the given value. If T is a plain pointer,
// value must not be nullptr. After calling this constructor, calls to
// ValueOrDie() will succeed, and calls to status() will return OK.
//
// NOTE: Not explicit - we want to use StatusOr<T> as a return type
// so it is convenient and sensible to be able to do 'return T()'
// when the return type is StatusOr<T>.
//
// REQUIRES: if T is a plain pointer, value != nullptr. This requirement is
// DCHECKed. In optimized builds, passing a nullptr pointer here will have
// the effect of passing ::private_join_and_compute::StatusCode::kInternal as a fallback.
StatusOr(const T& value); // NOLINT - no explicit
// Copy constructor.
StatusOr(const StatusOr& other);
// Assignment operator.
StatusOr& operator=(const StatusOr& other);
// Move constructor and move-assignment operator.
StatusOr(StatusOr&& other) = default;
StatusOr& operator=(StatusOr&& other) = default;
// Rvalue-reference overloads of the other constructors and assignment
// operators, to support move-only types and avoid unnecessary copying.
StatusOr(T&& value); // NOLINT - no explicit
// Returns a reference to our status. If this contains a T, then
// returns Status::OK.
const Status& status() const;
// Returns this->status().ok()
bool ok() const;
// Returns a reference to our current value, or CHECK-fails if !this->ok().
const T& ValueOrDie() const&;
T& ValueOrDie() &;
const T&& ValueOrDie() const&&;
T&& ValueOrDie() &&;
// Ignores any errors. This method does nothing except potentially suppress
// complaints from any tools that are checking that errors are not dropped on
// the floor.
void IgnoreError() const {}
private:
// absl::variant<Status, T> variant_;
Status status_;
std::unique_ptr<T> value_;
};
////////////////////////////////////////////////////////////////////////////////
// Implementation details for StatusOr<T>
namespace internal {
class StatusOrHelper {
public:
// Move type-agnostic error handling to the .cc.
static Status HandleInvalidStatusCtorArg();
static Status HandleNullObjectCtorArg();
static void Crash(const Status& status);
// Customized behavior for StatusOr<T> vs. StatusOr<T*>
template <typename T>
struct Specialize;
};
template <typename T>
struct StatusOrHelper::Specialize {
// For non-pointer T, a reference can never be nullptr.
static inline bool IsValueNull(const T& t) { return false; }
};
template <typename T>
struct StatusOrHelper::Specialize<T*> {
static inline bool IsValueNull(const T* t) { return t == nullptr; }
};
} // namespace internal
template <typename T>
inline StatusOr<T>::StatusOr() : status_(Status::UNKNOWN()), value_(nullptr) {}
template <typename T>
inline StatusOr<T>::StatusOr(const Status& status)
: status_(status), value_(nullptr) {
if (status.ok()) {
status_ = internal::StatusOrHelper::HandleInvalidStatusCtorArg();
}
}
template <typename T>
inline StatusOr<T>::StatusOr(const T& value)
: status_(Status::OK()), value_(new T(value)) {
if (internal::StatusOrHelper::Specialize<T>::IsValueNull(*value_)) {
status_ = internal::StatusOrHelper::HandleNullObjectCtorArg();
}
}
template <typename T>
inline StatusOr<T>::StatusOr(const StatusOr& other)
: status_(other.status_), value_(new T(*other.value_)) {}
template <typename T>
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
status_ = other.status_;
value_.reset(new T(*other.value_));
return *this;
}
template <typename T>
inline StatusOr<T>::StatusOr(T&& value)
: status_(Status::OK()), value_(new T(std::forward<T>(value))) {
if (internal::StatusOrHelper::Specialize<T>::IsValueNull(*value_)) {
status_ = internal::StatusOrHelper::HandleNullObjectCtorArg();
}
}
template <typename T>
inline const Status& StatusOr<T>::status() const {
return status_;
}
template <typename T>
inline bool StatusOr<T>::ok() const {
return status_.ok();
}
template <typename T>
inline const T& StatusOr<T>::ValueOrDie() const& {
if (value_ == nullptr) {
internal::StatusOrHelper::Crash(status());
}
return *value_;
}
template <typename T>
inline T& StatusOr<T>::ValueOrDie() & {
if (value_ == nullptr) {
internal::StatusOrHelper::Crash(status());
}
return *value_;
}
template <typename T>
inline const T&& StatusOr<T>::ValueOrDie() const&& {
if (value_ == nullptr) {
internal::StatusOrHelper::Crash(status());
}
return std::move(*value_);
}
template <typename T>
inline T&& StatusOr<T>::ValueOrDie() && {
if (value_ == nullptr) {
internal::StatusOrHelper::Crash(status());
}
return std::move(*value_);
}
} // namespace private_join_and_compute
#endif // UTIL_STATUSOR_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment