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