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 Camenisch-Shoup cryptosystem. 17 // 18 // Jan Camenisch, Victor Shoup. "Practical verifiable 19 // encryption and decryption of discrete logarithms" 20 // Advances in Cryptology - CRYPTO 2003. 21 // This header defines the class CamenischShoup, representing a key for the 22 // Camenisch Shoup cryptosystem. It can be initialized with or without the 23 // private (decryption) key. 24 // The class, once initialized, allows encryption and decryption of messages. 25 // The implementation here does not include the portion of the ciphertext, 26 // corresponding to non-malleability, as described in [CS'03]. 27 // 28 // Example Usage: 29 // Context ctx; 30 // CamenischShoupKey key = GenerateCamenischShoupKey(&ctx, n_length_bits, s, 31 // vector_encryption_length); 32 // PrivateCamenischShoup private_key(&ctx, key.n, key.s, key.g, key.xs, 33 // key.ys); 34 // CamenischShoupCiphertext ct = key.Encrypt(ms); 35 36 #ifndef PRIVATE_JOIN_AND_COMPUTE_CRYPTO_CAMENISCH_SHOUP_H_ 37 #define PRIVATE_JOIN_AND_COMPUTE_CRYPTO_CAMENISCH_SHOUP_H_ 38 39 #include <cstdint> 40 #include <map> 41 #include <memory> 42 #include <utility> 43 #include <vector> 44 45 #include "private_join_and_compute/crypto/big_num.h" 46 #include "private_join_and_compute/crypto/context.h" 47 #include "private_join_and_compute/crypto/fixed_base_exp.h" 48 #include "private_join_and_compute/crypto/proto/camenisch_shoup.pb.h" 49 #include "private_join_and_compute/util/status.inc" 50 51 namespace private_join_and_compute { 52 53 struct CamenischShoupCiphertext { 54 // For public key (g,ys,n), messages ms, and randomness r and power s: 55 // u = g^r mod n^(s+1) 56 // es[i] = (1+n)^ms[i] * ys[i]^r mod n^(s+1) 57 BigNum u; 58 std::vector<BigNum> es; 59 }; 60 61 // Holds a single Camenisch-Shoup ciphertext, together with the randomness used 62 // to encrypt. 63 struct CamenischShoupCiphertextWithRand { 64 CamenischShoupCiphertext ct; 65 BigNum r; 66 }; 67 68 // Returns a BigNum g that is a random (n^s)-th residue modulo 69 // n^(s+1). Computed as g = x^(2n^s) mod n^(s+1) for random x in Z_(n^(s+1)). 70 // Assumes that n is a product of 2 safe primes. 71 BigNum GetGeneratorForCamenischShoup(Context* ctx, const BigNum& n, uint64_t s); 72 73 struct CamenischShoupKey { 74 BigNum p; // A safe prime. 75 BigNum q; // A different safe prime. 76 BigNum n; // p * q 77 uint64_t s; // n^(s+1) is the modulus for the scheme. 78 uint64_t vector_encryption_length; // The number of ys and xs per ciphertext. 79 BigNum g; // A random 2(n^s)-th residue mod n^(s+1). 80 std::vector<BigNum> ys; // ys[i] = g^xs[i] mod n^(s+1) 81 // Each x in xs is a secret key, a random value between 0 and n, relatively 82 // prime to n. 83 std::vector<BigNum> xs; 84 }; 85 86 struct CamenischShoupPublicKey { 87 BigNum n; // p * q, for secret p and q. 88 uint64_t s; // n^(s+1) is the modulus for the scheme. 89 uint64_t vector_encryption_length; // The number of ys and xs per ciphertext. 90 BigNum g; // A random 2(n^s)-th residue mod n^(s+1). 91 // ys[i] = g^xs[i] mod n^(s+1) for xs in the secret key 92 std::vector<BigNum> ys; 93 }; 94 95 struct CamenischShoupPrivateKey { 96 // ys[i] = g^xs[i] mod n^(s+1) for all other values in the public key. 97 std::vector<BigNum> xs; 98 }; 99 100 // Generates a new key for the Camenisch-Shoup cryptosystem. 101 CamenischShoupKey GenerateCamenischShoupKey(Context* ctx, int n_length_bits, 102 uint64_t s, 103 uint64_t vector_encryption_length); 104 105 // Generates a new key pair for the Camenisch-Shoup cryptosystem. Assumes that 106 // the modulus n has been correctly generated elsewhere as the product of 2 107 // sufficiently long safe (or pseudo-safe) primes. 108 std::pair<std::unique_ptr<CamenischShoupPublicKey>, 109 std::unique_ptr<CamenischShoupPrivateKey>> 110 GenerateCamenischShoupKeyPair(Context* ctx, const BigNum& n, uint64_t s, 111 uint64_t vector_encryption_length); 112 113 // Creates a proto from the PublicKey struct. 114 proto::CamenischShoupPublicKey CamenischShoupPublicKeyToProto( 115 const CamenischShoupPublicKey& public_key); 116 // Parses PublicKey proto into a struct. 117 StatusOr<CamenischShoupPublicKey> ParseCamenischShoupPublicKeyProto( 118 Context* ctx, const proto::CamenischShoupPublicKey& public_key_proto); 119 // Creates a proto from the PrivateKey struct. 120 proto::CamenischShoupPrivateKey CamenischShoupPrivateKeyToProto( 121 const CamenischShoupPrivateKey& private_key); 122 // Parses PrivateKey proto into a struct. 123 StatusOr<CamenischShoupPrivateKey> ParseCamenischShoupPrivateKeyProto( 124 Context* ctx, const proto::CamenischShoupPrivateKey& private_key_proto); 125 // Creates a proto from the Ciphertext struct. 126 proto::CamenischShoupCiphertext CamenischShoupCiphertextToProto( 127 const CamenischShoupCiphertext& ciphertext); 128 129 // The classes below implement the Camenisch-Shoup cryptosystem. 130 // Does not include features of [CS'03] corresponding to non-malleability of 131 // ciphertexts. 132 133 class PublicCamenischShoup { 134 public: 135 // Initializes a public key for the Camenisch-Shoup cryptosystem. 136 // Accepts modulus n which is the product of safe primes p and q, a power s, 137 // random n-th residue g modulo n^(s+1), and y = g^x for unknown x. Also 138 // accepts a Context, of which it doesn't take ownership. 139 PublicCamenischShoup(Context* ctx, const BigNum& n, uint64_t s, 140 const BigNum& g, std::vector<BigNum> ys); 141 142 // Parses the key proto and creates a PublicCamenischShoup. Fails when 143 // parsing fails. 144 static StatusOr<std::unique_ptr<PublicCamenischShoup>> FromProto( 145 Context* ctx, const proto::CamenischShoupPublicKey& public_key_proto); 146 147 // PublicCamenischShoup is neither copyable nor movable. 148 PublicCamenischShoup(const PublicCamenischShoup&) = delete; 149 PublicCamenischShoup& operator=(const PublicCamenischShoup&) = delete; 150 PublicCamenischShoup(PublicCamenischShoup&&) = delete; 151 PublicCamenischShoup& operator=(PublicCamenischShoup&&) = delete; 152 ~PublicCamenischShoup() = default; 153 154 // Encrypts a message as (u = g^r mod n^(s+1), es) where es[i] = ys[i]^r * 155 // (1+n)^ms[i] mod n^(s+1)). If |ms| < |ys_|, the remaining messages are 156 // implicitly 0. 157 // 158 // Returns INVALID_ARGUMENT if the message is not >= 0, or if |ms| is > |ys_|. 159 StatusOr<CamenischShoupCiphertext> Encrypt(const std::vector<BigNum>& ms); 160 161 // Encrypts a message as in Encrypt, and also returns the randomness used for 162 // encryption. 163 StatusOr<CamenischShoupCiphertextWithRand> EncryptAndGetRand( 164 const std::vector<BigNum>& ms); 165 166 // Encrypts a message as (u = g^r mod n^(s+1), v = y^r * (1+n)^m mod n^(s+1)), 167 // using the randomness supplied. If |ms| < |ys_|, the remaining messages are 168 // implicitly 0. 169 // 170 // Returns INVALID_ARGUMENT if the message or randomness is not >= 0, or if 171 // |ms| is > |ys_|. 172 StatusOr<CamenischShoupCiphertext> EncryptWithRand( 173 const std::vector<BigNum>& ms, const BigNum& r); 174 175 // Homomorphically adds two ciphertexts mod n^(s+1). 176 CamenischShoupCiphertext Add(const CamenischShoupCiphertext& ct1, 177 const CamenischShoupCiphertext& ct2); 178 179 // Homomorphically multiplies a ciphertexts with a given scalar mod n. 180 CamenischShoupCiphertext Multiply(const CamenischShoupCiphertext& ct, 181 const BigNum& scalar); 182 183 // Parses a CamenischShoupCiphertext if it appears to be consistent with the 184 // key. 185 // 186 // Fails with INVALID_ARGUMENT if the ciphertext does not match the modulus, 187 // or has too many components. 188 StatusOr<CamenischShoupCiphertext> ParseCiphertextProto( 189 const proto::CamenischShoupCiphertext& ciphertext_proto); 190 191 // Getters g()192 inline const BigNum& g() const { return g_; } // generator ys()193 inline const std::vector<BigNum>& ys() const { return ys_; } // public keys n()194 inline const BigNum& n() const { return n_; } s()195 inline uint64_t s() const { return s_; } vector_encryption_length()196 inline uint64_t vector_encryption_length() const { 197 return vector_encryption_length_; 198 } modulus()199 inline const BigNum& modulus() const { return modulus_; } // = n^(s+1) message_upper_bound()200 inline const BigNum& message_upper_bound() const { return n_to_s_; } randomness_upper_bound()201 inline const BigNum& randomness_upper_bound() const { return n_; } 202 203 private: 204 Context* const ctx_; 205 const BigNum n_; 206 const uint64_t s_; 207 const uint64_t vector_encryption_length_; // = |ys|. 208 // Vector containing the n powers up to s+1 for faster computation. 209 const std::vector<BigNum> powers_of_n_; 210 // The vector holding values that are computed repeatedly when encrypting 211 // arbitrary messages via computing the binomial expansion of (1+n)^message. 212 // The binomial expansion of (1+n) to some arbitrary exponent has constant 213 // factors depending on only 1, n, and s regardless of the exponent value, 214 // this vector holds each of these fixed values for faster computation. 215 // Refer to Section 4.2 "Optimization of Encryption" from the 216 // Damgaard-Jurik-Nielsen paper for more information. 217 const std::vector<BigNum> encryption_precomp_; 218 const BigNum n_to_s_; 219 const BigNum modulus_; // equal to n^(s+1) 220 const BigNum g_; 221 const std::vector<BigNum> ys_; 222 // For fast computation of g^r mod n^(s+1). 223 const std::unique_ptr<FixedBaseExp> g_fbe_; 224 // For fast computation of y^r mod n^(s+1). 225 std::vector<std::unique_ptr<FixedBaseExp>> ys_fbe_; 226 }; 227 228 class PrivateCamenischShoup { 229 public: 230 // Initializes a private key for the Camenisch-Shoup cryptosystem. 231 // Accepts modulus n which is the product of safe primes p and q, a power s, 232 // and a random n-th residue g modulo n^(s+1). 233 // Also accepts x and y = g^x mod n^(s+1) for randomly selected x, where x 234 // serves as the secret key. x should be randomly chosen between 0 and n and 235 // relatively prime to n (i.e. x is in Z*n). 236 // Also accepts a Context, of which it doesn't take ownership. 237 // Returns a CHECK error if |ys| != |xs|. 238 PrivateCamenischShoup(Context* ctx, const BigNum& n, uint64_t s, 239 const BigNum& g, std::vector<BigNum> ys, 240 std::vector<BigNum> xs); 241 242 // Parses the key protos and creates a PrivateCamenischShoup. Fails when 243 // parsing fails. 244 static StatusOr<std::unique_ptr<PrivateCamenischShoup>> FromProto( 245 Context* ctx, const proto::CamenischShoupPublicKey& public_key_proto, 246 const proto::CamenischShoupPrivateKey& private_key_proto); 247 248 // PrivateCamenischShoup is neither copyable nor movable. 249 PrivateCamenischShoup(const PrivateCamenischShoup&) = delete; 250 PrivateCamenischShoup& operator=(const PrivateCamenischShoup&) = delete; 251 PrivateCamenischShoup(PrivateCamenischShoup&&) = delete; 252 PrivateCamenischShoup& operator=(PrivateCamenischShoup&&) = delete; 253 ~PrivateCamenischShoup() = default; 254 255 // Encrypts a message as (u = g^r mod n^2, v = y^r * (1+n)^m mod n^2). If |ms| 256 // < |ys_|, the remaining messages are implicitly 0. 257 // 258 // Returns INVALID_ARGUMENT if some message is not >= 0, or if |ms| > |ys_|. 259 StatusOr<CamenischShoupCiphertext> Encrypt(const std::vector<BigNum>& ms); 260 261 // Encrypts a message as in Encrypt, and also returns the randomness used for 262 // encryption. 263 StatusOr<CamenischShoupCiphertextWithRand> EncryptAndGetRand( 264 const std::vector<BigNum>& ms); 265 266 // Encrypts a message as (u = g^r mod n^2, v = y^r * (1+n)^m mod n^2), using 267 // the randomness supplied. If |ms| < |ys_|, the remaining messages are 268 // implicitly 0. 269 // 270 // Returns INVALID_ARGUMENT if some message or the randomness not >= 0, or if 271 // |ms| > |ys_|. 272 StatusOr<CamenischShoupCiphertext> EncryptWithRand( 273 const std::vector<BigNum>& ms, const BigNum& r); 274 275 // Decrypts a given Camenisch-Shoup cipertext and returns the encrypted 276 // message reduced mod n. Computes: ms such that (1+n)^ms[i] = (es[i] / 277 // u^xs[i] mod n^(s+1)). 278 // 279 // Returns INVALID_ARGUMENT if the ciphertext is invalid/ cannot be decrypted. 280 // Expects vector_encryption_length components in the ciphertext. 281 StatusOr<std::vector<BigNum>> Decrypt(const CamenischShoupCiphertext& ct); 282 283 // Parses a CamenischShoupCiphertext if it appears to be consistent with the 284 // key. 285 // 286 // Fails with INVALID_ARGUMENT if the ciphertext does not match the modulus, 287 // or has too many components. 288 StatusOr<CamenischShoupCiphertext> ParseCiphertextProto( 289 const proto::CamenischShoupCiphertext& ciphertext_proto); 290 291 // Getters g()292 inline const BigNum& g() { return g_; } // generator ys()293 inline const std::vector<BigNum>& ys() { return ys_; } // public keys xs()294 inline const std::vector<BigNum>& xs() { return xs_; } // secret keys n()295 inline const BigNum& n() { return n_; } s()296 inline uint64_t s() { return s_; } modulus()297 inline const BigNum& modulus() { return modulus_; } vector_encryption_length()298 inline uint64_t vector_encryption_length() { 299 return vector_encryption_length_; 300 } 301 302 private: 303 Context* const ctx_; 304 const BigNum n_; 305 const uint64_t s_; 306 const uint64_t vector_encryption_length_; // = |ys| = |xs|. 307 // Vector containing the n powers up to s+1 for faster computation. 308 const std::vector<BigNum> powers_of_n_; 309 // The vector holding values that are computed repeatedly when encrypting 310 // arbitrary messages via computing the binomial expansion of (1+n)^message. 311 // The binomial expansion of (1+n) to some arbitrary exponent has constant 312 // factors depending on only 1, n, and s regardless of the exponent value, 313 // this vector holds each of these fixed values for faster computation. 314 // Refer to Section 4.2 "Optimization of Encryption" from the 315 // Damgaard-Jurik-Nielsen paper for more information. 316 const std::vector<BigNum> encryption_precomp_; 317 // Intermediate values used repeatedly in decryption. 318 std::map<std::pair<int, int>, BigNum> decryption_precomp_; 319 const BigNum n_to_s_; 320 const BigNum modulus_; // equal to n^(s+1) 321 const BigNum g_; 322 const std::vector<BigNum> ys_; 323 const std::vector<BigNum> xs_; // secret key 324 std::unique_ptr<FixedBaseExp> g_fbe_; 325 std::vector<std::unique_ptr<FixedBaseExp>> ys_fbe_; 326 }; 327 328 } // namespace private_join_and_compute 329 330 #endif // PRIVATE_JOIN_AND_COMPUTE_CRYPTO_CAMENISCH_SHOUP_H_ 331