xref: /aosp_15_r20/external/private-join-and-compute/private_join_and_compute/crypto/elgamal.h (revision a6aa18fbfbf9cb5cd47356a9d1b057768998488c)
1 /*
2  * Copyright 2019 Google LLC.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     https://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 // Implementation of the ElGamal encryption scheme, over an Elliptic Curve.
17 //
18 // ElGamal is a multiplicatively homomorphic encryption scheme. See [1] for
19 // more information.
20 //
21 // The function elgamal::GenerateKeyPair generates a fresh public-private key
22 // pair for the scheme. Using these keys, one can instantiate ElGamalEncrypter
23 // and ElGamalDecrypter objects, which allow encrypting and decrypting
24 // messages that lie on the elliptic curve.
25 //
26 // The function elgamal::Mul allows homomorphic multiplication of two
27 // ciphertexts. The function elgamal::Exp allows homomorphic exponentiation of
28 // a ciphertext by a scalar.
29 // (Note: these operations actually correspond to addition and multiplication
30 // in the underlying EC group, but we refer to them as multiplication and
31 // exponentiation to match the standard description of ElGamal as
32 // multiplicatively homomorphic.)
33 //
34 // [1] https://en.wikipedia.org/wiki/ElGamal_encryption
35 
36 #ifndef PRIVATE_JOIN_AND_COMPUTE_CRYPTO_ELGAMAL_H_
37 #define PRIVATE_JOIN_AND_COMPUTE_CRYPTO_ELGAMAL_H_
38 
39 #include <memory>
40 #include <utility>
41 #include <vector>
42 
43 #include "private_join_and_compute/crypto/ec_group.h"
44 #include "private_join_and_compute/crypto/ec_point.h"
45 #include "private_join_and_compute/util/status.inc"
46 
47 namespace private_join_and_compute {
48 
49 class BigNum;
50 class ECPoint;
51 class ECGroup;
52 
53 // Containers and utility functions
54 namespace elgamal {
55 
56 struct Ciphertext {
57   // Encryption of an ECPoint m using randomness r, under public key (g,y).
58   ECPoint u;  // = g^r
59   ECPoint e;  // = m * y^r
60 };
61 
62 struct PublicKey {
63   ECPoint g;
64   ECPoint y;  // = g^x, where x is the secret key.
65 };
66 
67 struct PrivateKey {
68   BigNum x;
69 };
70 
71 // Generates a new ElGamal public-private key pair.
72 StatusOr<std::pair<std::unique_ptr<PublicKey>, std::unique_ptr<PrivateKey>>>
73 GenerateKeyPair(const ECGroup& ec_group);
74 
75 // Joins the public key shares in a public key. The shares should be nonempty.
76 StatusOr<std::unique_ptr<PublicKey>> GeneratePublicKeyFromShares(
77     const std::vector<std::unique_ptr<elgamal::PublicKey>>& shares);
78 
79 // Homomorphically multiply two ciphertexts.
80 // (Note: this corresponds to addition in the EC group.)
81 StatusOr<elgamal::Ciphertext> Mul(const elgamal::Ciphertext& ciphertext1,
82                                   const elgamal::Ciphertext& ciphertext2);
83 
84 // Homomorphically exponentiate a ciphertext by a scalar.
85 // (Note: this corresponds to multiplication in the EC group.)
86 StatusOr<elgamal::Ciphertext> Exp(const elgamal::Ciphertext& ciphertext,
87                                   const BigNum& scalar);
88 
89 // Returns a ciphertext encrypting the point at infinity, using fixed randomness
90 // "0". This is a multiplicative identity for ElGamal ciphertexts.
91 StatusOr<Ciphertext> GetZero(const ECGroup* group);
92 
93 // A convenience function that creates a copy of this ciphertext with the same
94 // randomness and underlying message.
95 StatusOr<Ciphertext> CloneCiphertext(const Ciphertext& ciphertext);
96 
97 // Checks if the given ciphertext is an encryption of the point of infinity
98 // using randomness "0".
99 bool IsCiphertextZero(const Ciphertext& ciphertext);
100 
101 }  // namespace elgamal
102 
103 // Implements ElGamal encryption with a public key.
104 class ElGamalEncrypter {
105  public:
106   // Creates a ElGamalEncrypter object from a given public key.
107   // Takes ownership of the public key.
108   ElGamalEncrypter(const ECGroup* ec_group,
109                    std::unique_ptr<elgamal::PublicKey> elgamal_public_key);
110 
111   // ElGamalEncrypter cannot be copied or assigned
112   ElGamalEncrypter(const ElGamalEncrypter&) = delete;
113   ElGamalEncrypter operator=(const ElGamalEncrypter&) = delete;
114 
115   ~ElGamalEncrypter() = default;
116 
117   // Encrypts a message m, that has already been mapped onto the curve.
118   StatusOr<elgamal::Ciphertext> Encrypt(const ECPoint& message) const;
119 
120   // Re-randomizes a ciphertext. After the re-randomization, the new ciphertext
121   // is an encryption of the same message as before.
122   StatusOr<elgamal::Ciphertext> ReRandomize(
123       const elgamal::Ciphertext& elgamal_ciphertext) const;
124 
125   // Returns a pointer to the owned ElGamal public key
getPublicKey()126   const elgamal::PublicKey* getPublicKey() const { return public_key_.get(); }
127 
128  private:
129   const ECGroup* ec_group_;  // not owned
130   std::unique_ptr<elgamal::PublicKey> public_key_;
131 };
132 
133 // Implements ElGamal decryption using the private key.
134 class ElGamalDecrypter {
135  public:
136   // Creates a ElGamalDecrypter object from a given private key.
137   // Takes ownership of the private key.
138   explicit ElGamalDecrypter(
139       std::unique_ptr<elgamal::PrivateKey> elgamal_private_key);
140 
141   // ElGamalDecrypter cannot be copied or assigned
142   ElGamalDecrypter(const ElGamalDecrypter&) = delete;
143   ElGamalDecrypter operator=(const ElGamalDecrypter&) = delete;
144 
145   ~ElGamalDecrypter() = default;
146 
147   // Decrypts a given ElGamal ciphertext.
148   StatusOr<ECPoint> Decrypt(const elgamal::Ciphertext& ciphertext) const;
149 
150   // Partially decrypts a given ElGamal ciphertext with a share of the secret
151   // key. The caller should rerandomize the ciphertext using the remaining
152   // partial public keys.
153   StatusOr<elgamal::Ciphertext> PartialDecrypt(
154       const elgamal::Ciphertext& ciphertext) const;
155 
156   // Returns a pointer to the owned ElGamal private key
getPrivateKey()157   const elgamal::PrivateKey* getPrivateKey() const {
158     return private_key_.get();
159   }
160 
161  private:
162   std::unique_ptr<elgamal::PrivateKey> private_key_;
163 };
164 
165 }  // namespace private_join_and_compute
166 
167 #endif  // PRIVATE_JOIN_AND_COMPUTE_CRYPTO_ELGAMAL_H_
168