aboutsummaryrefslogtreecommitdiff
path: root/private_join_and_compute/crypto/elgamal.h
blob: b9e0d977007b125d7f578360ac4abca2dfb61e77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * 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.
 */

// Implementation of the ElGamal encryption scheme, over an Elliptic Curve.
//
// ElGamal is a multiplicatively homomorphic encryption scheme. See [1] for
// more information.
//
// The function elgamal::GenerateKeyPair generates a fresh public-private key
// pair for the scheme. Using these keys, one can instantiate ElGamalEncrypter
// and ElGamalDecrypter objects, which allow encrypting and decrypting
// messages that lie on the elliptic curve.
//
// The function elgamal::Mul allows homomorphic multiplication of two
// ciphertexts. The function elgamal::Exp allows homomorphic exponentiation of
// a ciphertext by a scalar.
// (Note: these operations actually correspond to addition and multiplication
// in the underlying EC group, but we refer to them as multiplication and
// exponentiation to match the standard description of ElGamal as
// multiplicatively homomorphic.)
//
// [1] https://en.wikipedia.org/wiki/ElGamal_encryption

#ifndef CRYPTO_ELGAMAL_H_
#define CRYPTO_ELGAMAL_H_

#include <vector>

#include "private_join_and_compute/crypto/ec_group.h"
#include "private_join_and_compute/crypto/ec_point.h"
#include "private_join_and_compute/util/status.inc"

namespace private_join_and_compute {

class BigNum;
class ECPoint;
class ECGroup;

// Containers and utility functions
namespace elgamal {

struct Ciphertext {
  // Encryption of an ECPoint m using randomness r, under public key (g,y).
  ECPoint u;  // = g^r
  ECPoint e;  // = m * y^r
};

struct PublicKey {
  ECPoint g;
  ECPoint y;  // = g^x, where x is the secret key.
};

struct PrivateKey {
  BigNum x;
};

// Generates a new ElGamal public-private key pair.
StatusOr<std::pair<std::unique_ptr<PublicKey>, std::unique_ptr<PrivateKey>>>
GenerateKeyPair(const ECGroup& ec_group);

// Joins the public key shares in a public key. The shares should be nonempty.
StatusOr<std::unique_ptr<PublicKey>> GeneratePublicKeyFromShares(
    const std::vector<std::unique_ptr<elgamal::PublicKey>>& shares);

// Homomorphically multiply two ciphertexts.
// (Note: this corresponds to addition in the EC group.)
StatusOr<elgamal::Ciphertext> Mul(const elgamal::Ciphertext& ciphertext1,
                                  const elgamal::Ciphertext& ciphertext2);

// Homomorphically exponentiate a ciphertext by a scalar.
// (Note: this corresponds to multiplication in the EC group.)
StatusOr<elgamal::Ciphertext> Exp(const elgamal::Ciphertext& ciphertext,
                                  const BigNum& scalar);

// Returns a ciphertext encrypting the point at infinity, using fixed randomness
// "0". This is a multiplicative identity for ElGamal ciphertexts.
StatusOr<Ciphertext> GetZero(const ECGroup* group);

// A convenience function that creates a copy of this ciphertext with the same
// randomness and underlying message.
StatusOr<Ciphertext> CloneCiphertext(const Ciphertext& ciphertext);

// Checks if the given ciphertext is an encryption of the point of infinity
// using randomness "0".
bool IsCiphertextZero(const Ciphertext& ciphertext);

}  // namespace elgamal

// Implements ElGamal encryption with a public key.
class ElGamalEncrypter {
 public:
  // Creates a ElGamalEncrypter object from a given public key.
  // Takes ownership of the public key.
  ElGamalEncrypter(const ECGroup* ec_group,
                   std::unique_ptr<elgamal::PublicKey> elgamal_public_key);

  // ElGamalEncrypter cannot be copied or assigned
  ElGamalEncrypter(const ElGamalEncrypter&) = delete;
  ElGamalEncrypter operator=(const ElGamalEncrypter&) = delete;

  ~ElGamalEncrypter() = default;

  // Encrypts a message m, that has already been mapped onto the curve.
  StatusOr<elgamal::Ciphertext> Encrypt(const ECPoint& message) const;

  // Re-randomizes a ciphertext. After the re-randomization, the new ciphertext
  // is an encryption of the same message as before.
  StatusOr<elgamal::Ciphertext> ReRandomize(
      const elgamal::Ciphertext& elgamal_ciphertext) const;

  // Returns a pointer to the owned ElGamal public key
  const elgamal::PublicKey* getPublicKey() const { return public_key_.get(); }

 private:
  const ECGroup* ec_group_;  // not owned
  std::unique_ptr<elgamal::PublicKey> public_key_;
};

// Implements ElGamal decryption using the private key.
class ElGamalDecrypter {
 public:
  // Creates a ElGamalDecrypter object from a given private key.
  // Takes ownership of the private key.
  explicit ElGamalDecrypter(
      std::unique_ptr<elgamal::PrivateKey> elgamal_private_key);

  // ElGamalDecrypter cannot be copied or assigned
  ElGamalDecrypter(const ElGamalDecrypter&) = delete;
  ElGamalDecrypter operator=(const ElGamalDecrypter&) = delete;

  ~ElGamalDecrypter() = default;

  // Decrypts a given ElGamal ciphertext.
  StatusOr<ECPoint> Decrypt(const elgamal::Ciphertext& ciphertext) const;

  // Partially decrypts a given ElGamal ciphertext with a share of the secret
  // key. The caller should rerandomize the ciphertext using the remaining
  // partial public keys.
  StatusOr<elgamal::Ciphertext> PartialDecrypt(
      const elgamal::Ciphertext& ciphertext) const;

  // Returns a pointer to the owned ElGamal private key
  const elgamal::PrivateKey* getPrivateKey() const {
    return private_key_.get();
  }

 private:
  std::unique_ptr<elgamal::PrivateKey> private_key_;
};

}  // namespace private_join_and_compute

#endif  // CRYPTO_ELGAMAL_H_