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