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 #include "private_join_and_compute/crypto/dodis_yampolskiy_prf/bb_oblivious_signature.h"
17 
18 #include <stdint.h>
19 
20 #include <algorithm>
21 #include <cstddef>
22 #include <iterator>
23 #include <memory>
24 #include <string>
25 #include <tuple>
26 #include <utility>
27 #include <vector>
28 
29 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
30 #include "absl/strings/str_cat.h"
31 #include "private_join_and_compute/crypto/big_num.h"
32 #include "private_join_and_compute/crypto/camenisch_shoup.h"
33 #include "private_join_and_compute/crypto/context.h"
34 #include "private_join_and_compute/crypto/dodis_yampolskiy_prf/bb_oblivious_signature.pb.h"
35 #include "private_join_and_compute/crypto/ec_point.h"
36 #include "private_join_and_compute/crypto/pedersen_over_zn.h"
37 #include "private_join_and_compute/crypto/proto/big_num.pb.h"
38 #include "private_join_and_compute/crypto/proto/camenisch_shoup.pb.h"
39 #include "private_join_and_compute/crypto/proto/ec_point.pb.h"
40 #include "private_join_and_compute/crypto/proto/proto_util.h"
41 
42 namespace private_join_and_compute {
43 
44 namespace {
45 
46 // Helper functions to compute batched encryptions of Enc(a*(k + m + yr) + bq)
47 // given masked_messages (= am + bq), as, gammas (= ar), Enc(k), Enc(y), and the
48 // public_camenisch_shoup. Assumes that all sizes have been checked beforehand.
49 //
50 // Can be used for the "real" encryptions, the dummy encryptions, and the masked
51 // dummy encryptions.
52 StatusOr<std::vector<CamenischShoupCiphertext>>
GenerateHomomorphicCsCiphertexts(const std::vector<BigNum> & masked_messages,const std::vector<BigNum> & as,const std::vector<BigNum> & gammas,const std::vector<BigNum> & encryption_randomness,const std::vector<CamenischShoupCiphertext> & parsed_encrypted_k,const std::vector<CamenischShoupCiphertext> & parsed_encrypted_y,PublicCamenischShoup * public_camenisch_shoup)53 GenerateHomomorphicCsCiphertexts(
54     const std::vector<BigNum>& masked_messages, const std::vector<BigNum>& as,
55     const std::vector<BigNum>& gammas,
56     const std::vector<BigNum>& encryption_randomness,
57     const std::vector<CamenischShoupCiphertext>& parsed_encrypted_k,
58     const std::vector<CamenischShoupCiphertext>& parsed_encrypted_y,
59     PublicCamenischShoup* public_camenisch_shoup) {
60   // The messages are encrypted in batches of vector_encryption_length. We
61   // compute the number of Camenisch Shoup ciphertexts needed to cover the
62   // messages.
63   size_t num_camenisch_shoup_ciphertexts =
64       (masked_messages.size() +
65        public_camenisch_shoup->vector_encryption_length() - 1) /
66       public_camenisch_shoup->vector_encryption_length();
67 
68   std::vector<CamenischShoupCiphertext> encrypted_masked_messages;
69   encrypted_masked_messages.reserve(num_camenisch_shoup_ciphertexts);
70 
71   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
72     size_t batch_start_index =
73         i * public_camenisch_shoup->vector_encryption_length();
74     size_t batch_size = std::min(
75         public_camenisch_shoup->vector_encryption_length(),
76         static_cast<uint64_t>(masked_messages.size() - batch_start_index));
77     size_t batch_end_index = batch_start_index + batch_size;
78     // Determine the messages for the i'th batch.
79     std::vector<BigNum> masked_messages_for_batch_i(
80         masked_messages.begin() + batch_start_index,
81         masked_messages.begin() + batch_end_index);
82     ASSIGN_OR_RETURN(
83         CamenischShoupCiphertext encrypted_masked_message_at_i,
84         public_camenisch_shoup->EncryptWithRand(masked_messages_for_batch_i,
85                                                 encryption_randomness[i]));
86 
87     // Homomorphically add the appropriate a*k and a*r*y to the masked_message
88     // in the j'th slot, by using the encryption of k in the j'th slot and y in
89     // the j'th slot respectively (from the BbObliviousSignature public key).
90     for (uint64_t j = 0; j < batch_size; ++j) {
91       encrypted_masked_message_at_i = public_camenisch_shoup->Add(
92           encrypted_masked_message_at_i,
93           public_camenisch_shoup->Multiply(parsed_encrypted_k[j],
94                                            as[batch_start_index + j]));
95 
96       encrypted_masked_message_at_i = public_camenisch_shoup->Add(
97           encrypted_masked_message_at_i,
98           public_camenisch_shoup->Multiply(parsed_encrypted_y[j],
99                                            gammas[batch_start_index + j]));
100     }
101     encrypted_masked_messages.push_back(
102         std::move(encrypted_masked_message_at_i));
103   }
104   return std::move(encrypted_masked_messages);
105 }
106 
107 }  // namespace
108 
Create(proto::BbObliviousSignatureParameters parameters_proto,Context * ctx,ECGroup * ec_group,PublicCamenischShoup * public_camenisch_shoup,PedersenOverZn * pedersen)109 StatusOr<std::unique_ptr<BbObliviousSignature>> BbObliviousSignature::Create(
110     proto::BbObliviousSignatureParameters parameters_proto, Context* ctx,
111     ECGroup* ec_group, PublicCamenischShoup* public_camenisch_shoup,
112     PedersenOverZn* pedersen) {
113   if (ctx == nullptr) {
114     return absl::InvalidArgumentError(
115         "BbObliviousSignature::Create: The Context object is null.");
116   }
117   if (ec_group == nullptr) {
118     return absl::InvalidArgumentError(
119         "BbObliviousSignature::Create: The ECGroup object is null.");
120   }
121   if (public_camenisch_shoup == nullptr) {
122     return absl::InvalidArgumentError(
123         "BbObliviousSignature::Create: The PublicCamenischShoup object is "
124         "null.");
125   }
126   if (pedersen == nullptr) {
127     return absl::InvalidArgumentError(
128         "BbObliviousSignature::Create: The PedersenOverZn object is null.");
129   }
130   if (parameters_proto.security_parameter() <= 0) {
131     return absl::InvalidArgumentError(
132         "BbObliviousSignature::Create: security_parameter must be positive.");
133   }
134   if (parameters_proto.challenge_length_bits() <= 0) {
135     return absl::InvalidArgumentError(
136         "BbObliviousSignature::Create: challenge_length_bits must be "
137         "positive.");
138   }
139 
140   // dummy_masked_betas_bound is the largest value that should be encrypt-able
141   // by the Camenisch-Shoup scheme.
142   BigNum dummy_masked_betas_bound =
143       ctx->One()
144           .Lshift(2 * parameters_proto.challenge_length_bits() +
145                   2 * parameters_proto.security_parameter() + 1)
146           .Mul(ec_group->GetOrder())
147           .Mul(ec_group->GetOrder())
148           .Mul(ec_group->GetOrder());
149 
150   if (dummy_masked_betas_bound >
151       public_camenisch_shoup->message_upper_bound()) {
152     return absl::InvalidArgumentError(absl::StrCat(
153         "BbObliviousSignature::Create: Camenisch-Shoup encryption scheme is "
154         "not large enough to handle the messages in the proofs. Max message "
155         "size: ",
156         public_camenisch_shoup->message_upper_bound().ToDecimalString(),
157         ", message size needed for proof: ",
158         dummy_masked_betas_bound.ToDecimalString()));
159   }
160   if (dummy_masked_betas_bound > pedersen->n()) {
161     return absl::InvalidArgumentError(absl::StrCat(
162         "BbObliviousSignature::Create: Pedersen Modulus is "
163         "not large enough to handle the messages in the proofs. Max message "
164         "size: ",
165         pedersen->n().ToDecimalString(), ", message size needed for proof: ",
166         dummy_masked_betas_bound.ToDecimalString()));
167   }
168 
169   ASSIGN_OR_RETURN(ECPoint base_g,
170                    ec_group->CreateECPoint(parameters_proto.base_g()));
171 
172   return absl::WrapUnique(new BbObliviousSignature(
173       std::move(parameters_proto), ctx, ec_group, std::move(base_g),
174       public_camenisch_shoup, pedersen));
175 }
176 
177 StatusOr<std::tuple<proto::BbObliviousSignaturePublicKey,
178                     proto::BbObliviousSignaturePrivateKey>>
GenerateKeys()179 BbObliviousSignature::GenerateKeys() {
180   proto::BbObliviousSignaturePublicKey public_key_proto;
181   proto::BbObliviousSignaturePrivateKey private_key_proto;
182 
183   BigNum k = ec_group_->GeneratePrivateKey();
184   BigNum y = ec_group_->GeneratePrivateKey();
185   private_key_proto.set_k(k.ToBytes());
186   private_key_proto.set_y(y.ToBytes());
187 
188   public_key_proto.mutable_encrypted_k()->Reserve(
189       public_camenisch_shoup_->vector_encryption_length());
190   public_key_proto.mutable_encrypted_y()->Reserve(
191       public_camenisch_shoup_->vector_encryption_length());
192 
193   // The keys k and y should be encrypted vector_encryption_length times,
194   // separately for each slot of the ciphertext.
195   for (uint64_t i = 0; i < public_camenisch_shoup_->vector_encryption_length();
196        ++i) {
197     std::vector<BigNum> messages(
198         public_camenisch_shoup_->vector_encryption_length(), ctx_->Zero());
199     // Encrypt and push back k
200     messages[i] = k;
201     ASSIGN_OR_RETURN(CamenischShoupCiphertext k_ciphertext,
202                      public_camenisch_shoup_->Encrypt(messages));
203     *public_key_proto.add_encrypted_k() =
204         CamenischShoupCiphertextToProto(k_ciphertext);
205     // Encrypt and push back y
206     messages[i] = y;
207     ASSIGN_OR_RETURN(CamenischShoupCiphertext y_ciphertext,
208                      public_camenisch_shoup_->Encrypt(messages));
209     *public_key_proto.add_encrypted_y() =
210         CamenischShoupCiphertextToProto(y_ciphertext);
211   }
212 
213   return std::make_tuple(std::move(public_key_proto),
214                          std::move(private_key_proto));
215 }
216 
217 StatusOr<std::tuple<proto::BbObliviousSignatureRequest,
218                     proto::BbObliviousSignatureRequestProof,
219                     proto::BbObliviousSignatureRequestPrivateState>>
GenerateRequestAndProof(const std::vector<BigNum> & messages,const std::vector<BigNum> & rs,const proto::BbObliviousSignaturePublicKey & public_key,const PedersenOverZn::CommitmentAndOpening & commit_and_open_messages,const PedersenOverZn::CommitmentAndOpening & commit_and_open_rs)220 BbObliviousSignature::GenerateRequestAndProof(
221     const std::vector<BigNum>& messages, const std::vector<BigNum>& rs,
222     const proto::BbObliviousSignaturePublicKey& public_key,
223     const PedersenOverZn::CommitmentAndOpening& commit_and_open_messages,
224     const PedersenOverZn::CommitmentAndOpening& commit_and_open_rs) {
225   proto::BbObliviousSignatureRequest request_proto;
226   proto::BbObliviousSignatureRequestProof proof_proto;
227   proto::BbObliviousSignatureRequestPrivateState private_state_proto;
228 
229   // Check that sizes are compatible
230   if (messages.size() > pedersen_->gs().size()) {
231     return absl::InvalidArgumentError(absl::StrCat(
232         "BbObliviousSignature::GenerateRequest: messages has size ",
233         messages.size(),
234         " which is larger than the batch size supported by the Pedersen "
235         "commitment scheme (",
236         pedersen_->gs().size(), ")"));
237   }
238   if (rs.size() != messages.size()) {
239     return absl::InvalidArgumentError(absl::StrCat(
240         "BbObliviousSignature::GenerateRequest: rs has size ", messages.size(),
241         " which is different from messages (", messages.size(), ")"));
242   }
243 
244   // Generate all "a", "b" and "masked message" values.
245   // Each a is a random exponent in the EC group.
246   // Each b is a random value of size (2^(security_parameter + challenge_length)
247   // * q^2) where lambda is the security parameter, and q is the order of the
248   // ec_group in which we compute the BB Oblivious Signature. Each masked
249   // message is of the form a*m + b*q, which will be homomorphically added to
250   // a*k and ar * y to produce an encryption of a(k+m+yr) + b*q. We also compute
251   // alpha = a*m and gamma = a*r which will be needed for the proof.
252   std::vector<BigNum> as, bs, alphas, gammas, masked_messages;
253   as.reserve(messages.size());
254   bs.reserve(messages.size());
255   alphas.reserve(messages.size());
256   gammas.reserve(messages.size());
257   BigNum bs_bound = (ec_group_->GetOrder() * ec_group_->GetOrder())
258                         .Lshift(parameters_proto_.challenge_length_bits() +
259                                 parameters_proto_.security_parameter());
260   masked_messages.reserve(messages.size());
261   for (size_t i = 0; i < messages.size(); ++i) {
262     as.push_back(ec_group_->GeneratePrivateKey());
263     bs.push_back(ctx_->GenerateRandLessThan(bs_bound));
264     alphas.push_back(messages[i] * as.back());
265     gammas.push_back(rs[i] * as.back());
266     masked_messages.push_back(alphas.back() +
267                               (bs.back() * ec_group_->GetOrder()));
268   }
269 
270   // Parse the needed components of the public key.
271   std::vector<CamenischShoupCiphertext> parsed_encrypted_k;
272   parsed_encrypted_k.reserve(
273       public_camenisch_shoup_->vector_encryption_length());
274   std::vector<CamenischShoupCiphertext> parsed_encrypted_y;
275   parsed_encrypted_y.reserve(
276       public_camenisch_shoup_->vector_encryption_length());
277 
278   for (int i = 0; i < public_camenisch_shoup_->vector_encryption_length();
279        ++i) {
280     ASSIGN_OR_RETURN(CamenischShoupCiphertext cs_encrypt_k_at_i,
281                      public_camenisch_shoup_->ParseCiphertextProto(
282                          public_key.encrypted_k(i)));
283     parsed_encrypted_k.push_back(std::move(cs_encrypt_k_at_i));
284 
285     ASSIGN_OR_RETURN(CamenischShoupCiphertext cs_encrypt_y_at_i,
286                      public_camenisch_shoup_->ParseCiphertextProto(
287                          public_key.encrypted_y(i)));
288     parsed_encrypted_y.push_back(std::move(cs_encrypt_y_at_i));
289   }
290 
291   // The messages are encrypted in batches of vector_encryption_length. We
292   // compute the number of Camenisch Shoup ciphertexts needed to cover the
293   // messages.
294   size_t num_camenisch_shoup_ciphertexts =
295       (messages.size() + public_camenisch_shoup_->vector_encryption_length() -
296        1) /
297       public_camenisch_shoup_->vector_encryption_length();
298 
299   // Used for request proof.
300   std::vector<BigNum> encryption_randomness;
301   encryption_randomness.reserve(num_camenisch_shoup_ciphertexts);
302   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
303     encryption_randomness.push_back(
304         ctx_->GenerateRandLessThan(public_camenisch_shoup_->n()));
305   }
306 
307   ASSIGN_OR_RETURN(
308       std::vector<CamenischShoupCiphertext> encrypted_masked_messages,
309       GenerateHomomorphicCsCiphertexts(
310           masked_messages, as, gammas, encryption_randomness,
311           parsed_encrypted_k, parsed_encrypted_y, public_camenisch_shoup_));
312 
313   request_proto.set_num_messages(messages.size());
314   *private_state_proto.mutable_private_as() = BigNumVectorToProto(as);
315   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
316     *request_proto.add_repeated_encrypted_masked_messages() =
317         CamenischShoupCiphertextToProto(encrypted_masked_messages[i]);
318   }
319 
320   // Commit to as, bs.
321   // as must be committed separately in order to be able to homomorphically
322   // generate batch commitments to alphas and gammas. The i'th commitment
323   // contains as[i] in the i'th Pedersen batch-commitment slot, and 0s in all
324   // other slots.
325   std::vector<BigNum> commit_as, open_as;
326   commit_as.reserve(as.size());
327   open_as.reserve(as.size());
328   for (size_t i = 0; i < as.size(); ++i) {
329     std::vector<BigNum> ai_in_ith_position(pedersen_->gs().size(),
330                                            ctx_->Zero());
331     ai_in_ith_position[i] = as[i];
332     ASSIGN_OR_RETURN(PedersenOverZn::CommitmentAndOpening commit_and_open_ai,
333                      pedersen_->Commit(ai_in_ith_position));
334     commit_as.push_back(std::move(commit_and_open_ai.commitment));
335     open_as.push_back(std::move(commit_and_open_ai.opening));
336   }
337 
338   ASSIGN_OR_RETURN(PedersenOverZn::CommitmentAndOpening commit_and_open_bs,
339                    pedersen_->Commit(bs));
340 
341   // Homomorphically generate commitment to alphas, gammas. This
342   // homomorphically generated commitment will be used in 2 parts of the
343   // proof.
344   //
345   // Taking the example of alphas, recall that alphas[i] = as[i] *
346   // messages[i]. We want to show that alphas[i] was (1) properly used in
347   // computing encrypted_masked_messages, and (2) was properly generated as
348   // as[i]*messages[i]. For property (1), we need to show knowledge of
349   // alphas[i] and the randomness used to commit to alphas, and for property
350   // (2), we need to show that the commitment to alphas was homomorphically
351   // generated from Com(as[i]).
352 
353   // To support these proofs, we homomorphically generate Com(alpha) as
354   // (Prod_i Com(as[i])^messages[i]) * Com(0), where Com(0) is a fresh
355   // commitment to 0. Since we generated Com(as[i]) with as[i] each in a
356   // different Pedersen vector slot, this will correctly come out to a
357   // commitment of alpha, with overall commitment randomness (Sum_i open_as[i]
358   // * messages[i]) + open_alphas_2, where open_alphas_2 is the randomness
359   // used in the second commitment of 0. We will refer to the overall
360   // commitment randomness as open_alphas_1, and the randomness used to commit
361   // to 0 as open_alphas_2. These will be used in order to prove properties
362   // (1) and (2) respectively.
363   //
364   // We proceed similarly for gammas, where gammas[i] = as[i] * rs[i].
365   std::vector<BigNum> zero_vector(pedersen_->gs().size(), ctx_->Zero());
366   ASSIGN_OR_RETURN(
367       PedersenOverZn::CommitmentAndOpening temp_commit_and_open_alphas,
368       pedersen_->Commit(zero_vector));
369   ASSIGN_OR_RETURN(
370       PedersenOverZn::CommitmentAndOpening temp_commit_and_open_gammas,
371       pedersen_->Commit(zero_vector));
372 
373   // commit_alphas and commit_gammas serve as accumulators for the homomorphic
374   // computation. open_alphas_1 and open_gammas_1 will serve as accumulators
375   // for the randomness in these homomorphically generated commitments.
376   // open_alphas_2 and open_gammas_2 will serve to record the randomness used
377   // in the commitments to 0.
378   PedersenOverZn::Commitment commit_alphas =
379       std::move(temp_commit_and_open_alphas.commitment);
380   PedersenOverZn::Commitment commit_gammas =
381       std::move(temp_commit_and_open_gammas.commitment);
382   PedersenOverZn::Opening open_alphas_1 =
383       std::move(temp_commit_and_open_alphas.opening);
384   PedersenOverZn::Opening open_gammas_1 =
385       std::move(temp_commit_and_open_gammas.opening);
386   PedersenOverZn::Opening open_alphas_2 = open_alphas_1;
387   PedersenOverZn::Opening open_gammas_2 = open_gammas_1;
388 
389   for (size_t i = 0; i < messages.size(); ++i) {
390     commit_alphas = pedersen_->Add(
391         commit_alphas, pedersen_->Multiply(commit_as[i], messages[i]));
392     commit_gammas =
393         pedersen_->Add(commit_gammas, pedersen_->Multiply(commit_as[i], rs[i]));
394     open_alphas_1 = open_alphas_1 + (open_as[i] * messages[i]);
395     open_gammas_1 = open_gammas_1 + (open_as[i] * rs[i]);
396   }
397 
398   // Generate dummy exponents for all values
399   BigNum dummy_messages_bound =
400       ec_group_->GetOrder().Lshift(parameters_proto_.challenge_length_bits() +
401                                    parameters_proto_.security_parameter());
402   BigNum dummy_rs_bound = dummy_messages_bound;
403   BigNum dummy_as_bound = dummy_messages_bound;
404   BigNum dummy_bs_bound =
405       bs_bound.Lshift(parameters_proto_.challenge_length_bits() +
406                       parameters_proto_.security_parameter());
407   BigNum dummy_alphas_bound = dummy_as_bound * ec_group_->GetOrder();
408   BigNum dummy_gammas_bound = dummy_alphas_bound;
409   BigNum dummy_openings_bound =
410       pedersen_->n().Lshift(parameters_proto_.challenge_length_bits() +
411                             parameters_proto_.security_parameter());
412 
413   // The homomorphically computed openings for Com(alphas) and Com(gammas)
414   // need larger dummy values.
415   BigNum dummy_homomorphically_computed_openings_bound =
416       dummy_openings_bound * ec_group_->GetOrder() *
417       ctx_->CreateBigNum(messages.size() + 1);
418   BigNum dummy_encryption_randomness_bound =
419       public_camenisch_shoup_->n().Lshift(
420           parameters_proto_.challenge_length_bits() +
421           parameters_proto_.security_parameter());
422 
423   std::vector<BigNum> dummy_messages;
424   dummy_messages.reserve(messages.size());
425   std::vector<BigNum> dummy_rs;
426   dummy_rs.reserve(messages.size());
427   std::vector<BigNum> dummy_as;
428   dummy_as.reserve(messages.size());
429   std::vector<BigNum> dummy_as_openings;
430   dummy_as_openings.reserve(messages.size());
431   std::vector<BigNum> dummy_bs;
432   dummy_bs.reserve(messages.size());
433   std::vector<BigNum> dummy_alphas;
434   dummy_alphas.reserve(messages.size());
435   std::vector<BigNum> dummy_gammas;
436   dummy_gammas.reserve(messages.size());
437   std::vector<BigNum> dummy_masked_messages;
438   dummy_masked_messages.reserve(messages.size());
439 
440   for (size_t i = 0; i < messages.size(); ++i) {
441     dummy_messages.push_back(ctx_->GenerateRandLessThan(dummy_messages_bound));
442     dummy_rs.push_back(ctx_->GenerateRandLessThan(dummy_rs_bound));
443     dummy_as.push_back(ctx_->GenerateRandLessThan(dummy_as_bound));
444     dummy_as_openings.push_back(
445         ctx_->GenerateRandLessThan(dummy_openings_bound));
446     dummy_bs.push_back(ctx_->GenerateRandLessThan(dummy_bs_bound));
447     dummy_alphas.push_back(ctx_->GenerateRandLessThan(dummy_alphas_bound));
448     dummy_gammas.push_back(ctx_->GenerateRandLessThan(dummy_gammas_bound));
449     dummy_masked_messages.push_back(dummy_alphas.back() +
450                                     (dummy_bs.back() * ec_group_->GetOrder()));
451   }
452   BigNum dummy_messages_opening =
453       ctx_->GenerateRandLessThan(dummy_openings_bound);
454   BigNum dummy_rs_opening = ctx_->GenerateRandLessThan(dummy_openings_bound);
455   BigNum dummy_bs_opening = ctx_->GenerateRandLessThan(dummy_openings_bound);
456   BigNum dummy_alphas_opening_1 =
457       ctx_->GenerateRandLessThan(dummy_homomorphically_computed_openings_bound);
458   BigNum dummy_alphas_opening_2 =
459       ctx_->GenerateRandLessThan(dummy_openings_bound);
460   BigNum dummy_gammas_opening_1 =
461       ctx_->GenerateRandLessThan(dummy_homomorphically_computed_openings_bound);
462   BigNum dummy_gammas_opening_2 =
463       ctx_->GenerateRandLessThan(dummy_openings_bound);
464   std::vector<BigNum> dummy_encryption_randomness;
465   dummy_encryption_randomness.reserve(num_camenisch_shoup_ciphertexts);
466   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
467     dummy_encryption_randomness.push_back(
468         ctx_->GenerateRandLessThan(dummy_encryption_randomness_bound));
469   }
470 
471   // Create dummy composites for all values
472   ASSIGN_OR_RETURN(
473       PedersenOverZn::Commitment dummy_commit_messages,
474       pedersen_->CommitWithRand(dummy_messages, dummy_messages_opening));
475   ASSIGN_OR_RETURN(PedersenOverZn::Commitment dummy_commit_rs,
476                    pedersen_->CommitWithRand(dummy_rs, dummy_rs_opening));
477   std::vector<PedersenOverZn::Commitment> dummy_commit_as;
478   for (size_t i = 0; i < messages.size(); ++i) {
479     std::vector<BigNum> dummy_as_at_i = zero_vector;
480     dummy_as_at_i[i] = dummy_as[i];
481     ASSIGN_OR_RETURN(
482         PedersenOverZn::Commitment dummy_commit_as_at_i,
483         pedersen_->CommitWithRand(dummy_as_at_i, dummy_as_openings[i]));
484     dummy_commit_as.push_back(std::move(dummy_commit_as_at_i));
485   }
486   ASSIGN_OR_RETURN(PedersenOverZn::Commitment dummy_commit_bs,
487                    pedersen_->CommitWithRand(dummy_bs, dummy_bs_opening));
488   ASSIGN_OR_RETURN(
489       PedersenOverZn::Commitment dummy_commit_alphas_1,
490       pedersen_->CommitWithRand(dummy_alphas, dummy_alphas_opening_1));
491   ASSIGN_OR_RETURN(
492       PedersenOverZn::Commitment dummy_commit_gammas_1,
493       pedersen_->CommitWithRand(dummy_gammas, dummy_gammas_opening_1));
494 
495   ASSIGN_OR_RETURN(
496       PedersenOverZn::Commitment dummy_commit_alphas_2,
497       pedersen_->CommitWithRand(zero_vector, dummy_alphas_opening_2));
498   ASSIGN_OR_RETURN(
499       PedersenOverZn::Commitment dummy_commit_gammas_2,
500       pedersen_->CommitWithRand(zero_vector, dummy_gammas_opening_2));
501   for (size_t i = 0; i < messages.size(); ++i) {
502     dummy_commit_alphas_2 =
503         pedersen_->Add(dummy_commit_alphas_2,
504                        pedersen_->Multiply(commit_as[i], dummy_messages[i]));
505     dummy_commit_gammas_2 = pedersen_->Add(
506         dummy_commit_gammas_2, pedersen_->Multiply(commit_as[i], dummy_rs[i]));
507   }
508 
509   // Generate the dummy Camenisch Shoup encryptions.
510   ASSIGN_OR_RETURN(
511       std::vector<CamenischShoupCiphertext> dummy_encrypted_masked_messages,
512       GenerateHomomorphicCsCiphertexts(
513           dummy_masked_messages, dummy_as, dummy_gammas,
514           dummy_encryption_randomness, parsed_encrypted_k, parsed_encrypted_y,
515           public_camenisch_shoup_));
516 
517   // Serialize the statement and first message into protos, and generate the
518   // challenge
519   proto::BbObliviousSignatureRequestProof::Statement proof_statement;
520   *proof_statement.mutable_parameters() = parameters_proto_;
521   *proof_statement.mutable_public_key() = public_key;
522   proof_statement.set_commit_messages(
523       commit_and_open_messages.commitment.ToBytes());
524   proof_statement.set_commit_rs(commit_and_open_rs.commitment.ToBytes());
525   *proof_statement.mutable_commit_as() = BigNumVectorToProto(commit_as);
526   proof_statement.set_commit_bs(commit_and_open_bs.commitment.ToBytes());
527   proof_statement.set_commit_alphas(commit_alphas.ToBytes());
528   proof_statement.set_commit_gammas(commit_gammas.ToBytes());
529   *proof_statement.mutable_request() = request_proto;
530 
531   proto::BbObliviousSignatureRequestProof::Message1 proof_message_1;
532   proof_message_1.set_dummy_commit_messages(dummy_commit_messages.ToBytes());
533   proof_message_1.set_dummy_commit_rs(dummy_commit_rs.ToBytes());
534   *proof_message_1.mutable_dummy_commit_as() =
535       BigNumVectorToProto(dummy_commit_as);
536   proof_message_1.set_dummy_commit_bs(dummy_commit_bs.ToBytes());
537   proof_message_1.set_dummy_commit_alphas_1(dummy_commit_alphas_1.ToBytes());
538   proof_message_1.set_dummy_commit_alphas_2(dummy_commit_alphas_2.ToBytes());
539   proof_message_1.set_dummy_commit_gammas_1(dummy_commit_gammas_1.ToBytes());
540   proof_message_1.set_dummy_commit_gammas_2(dummy_commit_gammas_2.ToBytes());
541   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
542     *proof_message_1.add_repeated_dummy_encrypted_masked_messages() =
543         CamenischShoupCiphertextToProto(dummy_encrypted_masked_messages[i]);
544   }
545 
546   ASSIGN_OR_RETURN(BigNum challenge, GenerateRequestProofChallenge(
547                                          proof_statement, proof_message_1));
548 
549   // Create masked dummy openings
550   std::vector<BigNum> masked_dummy_messages;
551   masked_dummy_messages.reserve(messages.size());
552   std::vector<BigNum> masked_dummy_rs;
553   masked_dummy_rs.reserve(messages.size());
554   std::vector<BigNum> masked_dummy_as;
555   masked_dummy_as.reserve(messages.size());
556   std::vector<BigNum> masked_dummy_as_openings;
557   masked_dummy_as_openings.reserve(messages.size());
558   std::vector<BigNum> masked_dummy_bs;
559   masked_dummy_bs.reserve(messages.size());
560   std::vector<BigNum> masked_dummy_alphas;
561   masked_dummy_alphas.reserve(messages.size());
562   std::vector<BigNum> masked_dummy_gammas;
563   masked_dummy_gammas.reserve(messages.size());
564 
565   for (size_t i = 0; i < messages.size(); ++i) {
566     masked_dummy_messages.push_back(dummy_messages[i] +
567                                     challenge * messages[i]);
568     masked_dummy_rs.push_back(dummy_rs[i] + challenge * rs[i]);
569     masked_dummy_as.push_back(dummy_as[i] + challenge * as[i]);
570     masked_dummy_as_openings.push_back(dummy_as_openings[i] +
571                                        challenge * open_as[i]);
572     masked_dummy_bs.push_back(dummy_bs[i] + challenge * bs[i]);
573     masked_dummy_alphas.push_back(dummy_alphas[i] + challenge * alphas[i]);
574     masked_dummy_gammas.push_back(dummy_gammas[i] + challenge * gammas[i]);
575   }
576   BigNum masked_dummy_messages_opening =
577       dummy_messages_opening + challenge * commit_and_open_messages.opening;
578   BigNum masked_dummy_rs_opening =
579       dummy_rs_opening + challenge * commit_and_open_rs.opening;
580   BigNum masked_dummy_bs_opening =
581       dummy_bs_opening + challenge * commit_and_open_bs.opening;
582   BigNum masked_dummy_alphas_opening_1 =
583       dummy_alphas_opening_1 + challenge * open_alphas_1;
584   BigNum masked_dummy_alphas_opening_2 =
585       dummy_alphas_opening_2 + challenge * open_alphas_2;
586   BigNum masked_dummy_gammas_opening_1 =
587       dummy_gammas_opening_1 + challenge * open_gammas_1;
588   BigNum masked_dummy_gammas_opening_2 =
589       dummy_gammas_opening_2 + challenge * open_gammas_2;
590   std::vector<BigNum> masked_dummy_encryption_randomness;
591   masked_dummy_encryption_randomness.reserve(num_camenisch_shoup_ciphertexts);
592   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
593     masked_dummy_encryption_randomness.push_back(
594         dummy_encryption_randomness[i] + challenge * encryption_randomness[i]);
595   }
596 
597   // Generate proof proto.
598 
599   *proof_proto.mutable_commit_as() = BigNumVectorToProto(commit_as);
600   proof_proto.set_commit_bs(commit_and_open_bs.commitment.ToBytes());
601   proof_proto.set_commit_alphas(commit_alphas.ToBytes());
602   proof_proto.set_commit_gammas(commit_gammas.ToBytes());
603   proof_proto.set_challenge(challenge.ToBytes());
604 
605   proto::BbObliviousSignatureRequestProof::Message2* proof_proto_message_2 =
606       proof_proto.mutable_message_2();
607   *proof_proto_message_2->mutable_masked_dummy_messages() =
608       BigNumVectorToProto(masked_dummy_messages);
609   proof_proto_message_2->set_masked_dummy_messages_opening(
610       masked_dummy_messages_opening.ToBytes());
611   *proof_proto_message_2->mutable_masked_dummy_rs() =
612       BigNumVectorToProto(masked_dummy_rs);
613   proof_proto_message_2->set_masked_dummy_rs_opening(
614       masked_dummy_rs_opening.ToBytes());
615   *proof_proto_message_2->mutable_masked_dummy_as() =
616       BigNumVectorToProto(masked_dummy_as);
617   *proof_proto_message_2->mutable_masked_dummy_as_opening() =
618       BigNumVectorToProto(masked_dummy_as_openings);
619   *proof_proto_message_2->mutable_masked_dummy_bs() =
620       BigNumVectorToProto(masked_dummy_bs);
621   proof_proto_message_2->set_masked_dummy_bs_opening(
622       masked_dummy_bs_opening.ToBytes());
623   *proof_proto_message_2->mutable_masked_dummy_alphas() =
624       BigNumVectorToProto(masked_dummy_alphas);
625   proof_proto_message_2->set_masked_dummy_alphas_opening_1(
626       masked_dummy_alphas_opening_1.ToBytes());
627   proof_proto_message_2->set_masked_dummy_alphas_opening_2(
628       masked_dummy_alphas_opening_2.ToBytes());
629   *proof_proto_message_2->mutable_masked_dummy_gammas() =
630       BigNumVectorToProto(masked_dummy_gammas);
631   proof_proto_message_2->set_masked_dummy_gammas_opening_1(
632       masked_dummy_gammas_opening_1.ToBytes());
633   proof_proto_message_2->set_masked_dummy_gammas_opening_2(
634       masked_dummy_gammas_opening_2.ToBytes());
635   *proof_proto_message_2
636        ->mutable_masked_dummy_encryption_randomness_per_ciphertext() =
637       BigNumVectorToProto(masked_dummy_encryption_randomness);
638 
639   return std::make_tuple(std::move(request_proto), std::move(proof_proto),
640                          std::move(private_state_proto));
641 }
642 
643 // Verifies a signature request and proof.
VerifyRequest(const proto::BbObliviousSignaturePublicKey & public_key,const proto::BbObliviousSignatureRequest & request,const proto::BbObliviousSignatureRequestProof & request_proof,const PedersenOverZn::Commitment & commit_messages,const PedersenOverZn::Commitment & commit_rs)644 Status BbObliviousSignature::VerifyRequest(
645     const proto::BbObliviousSignaturePublicKey& public_key,
646     const proto::BbObliviousSignatureRequest& request,
647     const proto::BbObliviousSignatureRequestProof& request_proof,
648     const PedersenOverZn::Commitment& commit_messages,
649     const PedersenOverZn::Commitment& commit_rs) {
650   if (request.num_messages() > pedersen_->gs().size()) {
651     return absl::InvalidArgumentError(absl::StrCat(
652         "BbObliviousSignature::VerifyRequest: messages has size ",
653         request.num_messages(),
654         " which is larger than the pedersen batch size in parameters (",
655         pedersen_->gs().size(), ")"));
656   }
657   // Check that all vectors have the correct size.
658   if (request_proof.commit_as().serialized_big_nums_size() !=
659       request.num_messages()) {
660     return absl::InvalidArgumentError(
661         absl::StrCat("BbObliviousSignatures::VerifyRequest: request proof "
662                      "has wrong number of commit_as: expected ",
663                      request.num_messages(), ", actual ",
664                      request_proof.commit_as().serialized_big_nums_size()));
665   }
666   if (request_proof.message_2()
667           .masked_dummy_messages()
668           .serialized_big_nums_size() != request.num_messages()) {
669     return absl::InvalidArgumentError(absl::StrCat(
670         "BbObliviousSignatures::VerifyRequest: request proof has wrong "
671         "number of masked_dummy_messages: expected ",
672         request.num_messages(), ", actual ",
673         request_proof.message_2()
674             .masked_dummy_messages()
675             .serialized_big_nums_size()));
676   }
677   if (request_proof.message_2().masked_dummy_rs().serialized_big_nums_size() !=
678       request.num_messages()) {
679     return absl::InvalidArgumentError(absl::StrCat(
680         "BbObliviousSignatures::VerifyRequest: request proof has wrong "
681         "number of masked_dummy_rs: expected ",
682         request.num_messages(), ", actual ",
683         request_proof.message_2()
684             .masked_dummy_rs()
685             .serialized_big_nums_size()));
686   }
687   if (request_proof.message_2().masked_dummy_as().serialized_big_nums_size() !=
688       request.num_messages()) {
689     return absl::InvalidArgumentError(absl::StrCat(
690         "BbObliviousSignatures::VerifyRequest: request proof has wrong "
691         "number of masked_dummy_as: expected ",
692         request.num_messages(), ", actual ",
693         request_proof.message_2()
694             .masked_dummy_as()
695             .serialized_big_nums_size()));
696   }
697   if (request_proof.message_2().masked_dummy_bs().serialized_big_nums_size() !=
698       request.num_messages()) {
699     return absl::InvalidArgumentError(absl::StrCat(
700         "BbObliviousSignatures::VerifyRequest: request proof has wrong "
701         "number of masked_dummy_bs: expected ",
702         request.num_messages(), ", actual ",
703         request_proof.message_2()
704             .masked_dummy_bs()
705             .serialized_big_nums_size()));
706   }
707   if (request_proof.message_2()
708           .masked_dummy_alphas()
709           .serialized_big_nums_size() != request.num_messages()) {
710     return absl::InvalidArgumentError(absl::StrCat(
711         "BbObliviousSignatures::VerifyRequest: request proof has wrong "
712         "number of masked_dummy_alphas: expected ",
713         request.num_messages(), ", actual ",
714         request_proof.message_2()
715             .masked_dummy_alphas()
716             .serialized_big_nums_size()));
717   }
718   if (request_proof.message_2()
719           .masked_dummy_gammas()
720           .serialized_big_nums_size() != request.num_messages()) {
721     return absl::InvalidArgumentError(absl::StrCat(
722         "BbObliviousSignatures::VerifyRequest: request proof has wrong "
723         "number of masked_dummy_gammas: expected ",
724         request.num_messages(), ", actual ",
725         request_proof.message_2()
726             .masked_dummy_gammas()
727             .serialized_big_nums_size()));
728   }
729 
730   // The messages are encrypted in batches of vector_encryption_length. We
731   // compute the number of Camenisch Shoup ciphertexts needed to cover the
732   // messages.
733   size_t num_camenisch_shoup_ciphertexts =
734       (request.num_messages() +
735        public_camenisch_shoup_->vector_encryption_length() - 1) /
736       public_camenisch_shoup_->vector_encryption_length();
737 
738   if (request.repeated_encrypted_masked_messages_size() !=
739       num_camenisch_shoup_ciphertexts) {
740     return absl::InvalidArgumentError(
741         absl::StrCat("BbObliviousSignatures::VerifyRequest: request has wrong "
742                      "number of ciphertexts: expected ",
743                      num_camenisch_shoup_ciphertexts, ", actual ",
744                      request.repeated_encrypted_masked_messages_size()));
745   }
746   if (request_proof.message_2()
747           .masked_dummy_encryption_randomness_per_ciphertext()
748           .serialized_big_nums_size() != num_camenisch_shoup_ciphertexts) {
749     return absl::InvalidArgumentError(absl::StrCat(
750         "BbObliviousSignatures::VerifyRequest: request proof has wrong "
751         "number of masked_dummy_encryption_randomness: expected ",
752         num_camenisch_shoup_ciphertexts, ", actual ",
753         request_proof.message_2()
754             .masked_dummy_encryption_randomness_per_ciphertext()
755             .serialized_big_nums_size()));
756   }
757 
758   // Create the proof statement
759   proto::BbObliviousSignatureRequestProof::Statement proof_statement;
760   *proof_statement.mutable_parameters() = parameters_proto_;
761   *proof_statement.mutable_public_key() = public_key;
762   proof_statement.set_commit_messages(commit_messages.ToBytes());
763   proof_statement.set_commit_rs(commit_rs.ToBytes());
764   *proof_statement.mutable_commit_as() = request_proof.commit_as();
765   proof_statement.set_commit_bs(request_proof.commit_bs());
766   proof_statement.set_commit_alphas(request_proof.commit_alphas());
767   proof_statement.set_commit_gammas(request_proof.commit_gammas());
768   *proof_statement.mutable_request() = request;
769 
770   // Parse the components needed for the proof.
771   std::vector<PedersenOverZn::Commitment> commit_as =
772       ParseBigNumVectorProto(ctx_, request_proof.commit_as());
773   PedersenOverZn::Commitment commit_bs =
774       ctx_->CreateBigNum(request_proof.commit_bs());
775   PedersenOverZn::Commitment commit_alphas =
776       ctx_->CreateBigNum(request_proof.commit_alphas());
777   PedersenOverZn::Commitment commit_gammas =
778       ctx_->CreateBigNum(request_proof.commit_gammas());
779   std::vector<CamenischShoupCiphertext> encrypted_masked_messages;
780   encrypted_masked_messages.reserve(num_camenisch_shoup_ciphertexts);
781   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
782     ASSIGN_OR_RETURN(CamenischShoupCiphertext encrypted_masked_messages_at_i,
783                      public_camenisch_shoup_->ParseCiphertextProto(
784                          request.repeated_encrypted_masked_messages(i)));
785     encrypted_masked_messages.push_back(
786         std::move(encrypted_masked_messages_at_i));
787   }
788 
789   // Parse challenge from the proof.
790   BigNum challenge_from_proof = ctx_->CreateBigNum(request_proof.challenge());
791 
792   // Parse the masked dummy values from the proof.
793   std::vector<BigNum> masked_dummy_messages = ParseBigNumVectorProto(
794       ctx_, request_proof.message_2().masked_dummy_messages());
795   BigNum masked_dummy_messages_opening = ctx_->CreateBigNum(
796       request_proof.message_2().masked_dummy_messages_opening());
797   std::vector<BigNum> masked_dummy_rs =
798       ParseBigNumVectorProto(ctx_, request_proof.message_2().masked_dummy_rs());
799   BigNum masked_dummy_rs_opening =
800       ctx_->CreateBigNum(request_proof.message_2().masked_dummy_rs_opening());
801   std::vector<BigNum> masked_dummy_as =
802       ParseBigNumVectorProto(ctx_, request_proof.message_2().masked_dummy_as());
803   std::vector<BigNum> masked_dummy_as_opening = ParseBigNumVectorProto(
804       ctx_, request_proof.message_2().masked_dummy_as_opening());
805   std::vector<BigNum> masked_dummy_bs =
806       ParseBigNumVectorProto(ctx_, request_proof.message_2().masked_dummy_bs());
807   BigNum masked_dummy_bs_opening =
808       ctx_->CreateBigNum(request_proof.message_2().masked_dummy_bs_opening());
809   std::vector<BigNum> masked_dummy_alphas = ParseBigNumVectorProto(
810       ctx_, request_proof.message_2().masked_dummy_alphas());
811   BigNum masked_dummy_alphas_opening_1 = ctx_->CreateBigNum(
812       request_proof.message_2().masked_dummy_alphas_opening_1());
813   BigNum masked_dummy_alphas_opening_2 = ctx_->CreateBigNum(
814       request_proof.message_2().masked_dummy_alphas_opening_2());
815   std::vector<BigNum> masked_dummy_gammas = ParseBigNumVectorProto(
816       ctx_, request_proof.message_2().masked_dummy_gammas());
817   BigNum masked_dummy_gammas_opening_1 = ctx_->CreateBigNum(
818       request_proof.message_2().masked_dummy_gammas_opening_1());
819   BigNum masked_dummy_gammas_opening_2 = ctx_->CreateBigNum(
820       request_proof.message_2().masked_dummy_gammas_opening_2());
821   std::vector<BigNum> masked_dummy_encryption_randomness =
822       ParseBigNumVectorProto(
823           ctx_, request_proof.message_2()
824                     .masked_dummy_encryption_randomness_per_ciphertext());
825 
826   // Verify bounds.
827   BigNum masked_dummy_messages_bound =
828       ec_group_->GetOrder().Lshift(parameters_proto_.challenge_length_bits() +
829                                    parameters_proto_.security_parameter() + 1);
830   BigNum masked_dummy_rs_bound = masked_dummy_messages_bound;
831   BigNum masked_dummy_as_bound = masked_dummy_messages_bound;
832   BigNum masked_dummy_bs_bound =
833       (ec_group_->GetOrder() * ec_group_->GetOrder())
834           .Lshift(2 * parameters_proto_.challenge_length_bits() +
835                   2 * parameters_proto_.security_parameter() + 1);
836   BigNum masked_dummy_alphas_bound =
837       masked_dummy_as_bound * ec_group_->GetOrder();
838   BigNum masked_dummy_gammas_bound = masked_dummy_alphas_bound;
839 
840   for (uint64_t i = 0; i < request.num_messages(); ++i) {
841     if (masked_dummy_messages[i] >= masked_dummy_messages_bound) {
842       return absl::InvalidArgumentError(absl::StrCat(
843           "BbObliviousSignatures::VerifyRequest: The ", i,
844           "th entry of masked_dummy_messages,",
845           masked_dummy_messages[i].ToDecimalString(), " (bit length ",
846           masked_dummy_messages[i].BitLength(), ")",
847           ",is larger than the acceptable bound: ",
848           masked_dummy_messages_bound.ToDecimalString(), " (bit length ",
849           masked_dummy_messages_bound.BitLength(), ")"));
850     }
851     if (masked_dummy_as[i] >= masked_dummy_as_bound) {
852       return absl::InvalidArgumentError(absl::StrCat(
853           "BbObliviousSignatures::VerifyRequest: The ", i,
854           "th entry of masked_dummy_as,", masked_dummy_as[i].ToDecimalString(),
855           " (bit length ", masked_dummy_as[i].BitLength(), ")",
856           ",is larger than the acceptable bound: ",
857           masked_dummy_as_bound.ToDecimalString(), " (bit length ",
858           masked_dummy_as_bound.BitLength(), ")"));
859     }
860     if (masked_dummy_bs[i] >= masked_dummy_bs_bound) {
861       return absl::InvalidArgumentError(absl::StrCat(
862           "BbObliviousSignatures::VerifyRequest: The ", i,
863           "th entry of masked_dummy_bs,", masked_dummy_bs[i].ToDecimalString(),
864           " (bit length ", masked_dummy_bs[i].BitLength(), ")",
865           ",is larger than the acceptable bound: ",
866           masked_dummy_bs_bound.ToDecimalString(), " (bit length ",
867           masked_dummy_bs_bound.BitLength(), ")"));
868     }
869     if (masked_dummy_alphas[i] >= masked_dummy_alphas_bound) {
870       return absl::InvalidArgumentError(absl::StrCat(
871           "BbObliviousSignatures::VerifyRequest: The ", i,
872           "th entry of masked_dummy_alphas,",
873           masked_dummy_alphas[i].ToDecimalString(), " (bit length ",
874           masked_dummy_alphas[i].BitLength(), ")",
875           ",is larger than the acceptable bound: ",
876           masked_dummy_alphas_bound.ToDecimalString(), " (bit length ",
877           masked_dummy_alphas_bound.BitLength(), ")"));
878     }
879     if (masked_dummy_gammas[i] >= masked_dummy_gammas_bound) {
880       return absl::InvalidArgumentError(absl::StrCat(
881           "BbObliviousSignatures::VerifyRequest: The ", i,
882           "th entry of masked_dummy_gammas,",
883           masked_dummy_gammas[i].ToDecimalString(), " (bit length ",
884           masked_dummy_gammas[i].BitLength(), ")",
885           ",is larger than the acceptable bound: ",
886           masked_dummy_gammas_bound.ToDecimalString(), " (bit length ",
887           masked_dummy_gammas_bound.BitLength(), ")"));
888     }
889   }
890 
891   // Create masked dummy composite values
892 
893   ASSIGN_OR_RETURN(PedersenOverZn::Commitment masked_dummy_commit_messages,
894                    pedersen_->CommitWithRand(masked_dummy_messages,
895                                              masked_dummy_messages_opening));
896   ASSIGN_OR_RETURN(
897       PedersenOverZn::Commitment masked_dummy_commit_rs,
898       pedersen_->CommitWithRand(masked_dummy_rs, masked_dummy_rs_opening));
899 
900   std::vector<PedersenOverZn::Commitment> masked_dummy_commit_as;
901   masked_dummy_commit_as.reserve(commit_as.size());
902   std::vector<BigNum> zero_vector(pedersen_->gs().size(), ctx_->Zero());
903   for (size_t i = 0; i < commit_as.size(); ++i) {
904     std::vector<BigNum> masked_dummy_ai_at_i = zero_vector;
905     masked_dummy_ai_at_i[i] = masked_dummy_as[i];
906     ASSIGN_OR_RETURN(PedersenOverZn::Commitment masked_dummy_commit_ai,
907                      pedersen_->CommitWithRand(masked_dummy_ai_at_i,
908                                                masked_dummy_as_opening[i]));
909     masked_dummy_commit_as.push_back(masked_dummy_commit_ai);
910   }
911   ASSIGN_OR_RETURN(
912       PedersenOverZn::Commitment masked_dummy_commit_bs,
913       pedersen_->CommitWithRand(masked_dummy_bs, masked_dummy_bs_opening));
914   ASSIGN_OR_RETURN(PedersenOverZn::Commitment masked_dummy_commit_alphas_1,
915                    pedersen_->CommitWithRand(masked_dummy_alphas,
916                                              masked_dummy_alphas_opening_1));
917   ASSIGN_OR_RETURN(PedersenOverZn::Commitment masked_dummy_commit_gammas_1,
918                    pedersen_->CommitWithRand(masked_dummy_gammas,
919                                              masked_dummy_gammas_opening_1));
920 
921   // masked_dummy_alphas_2 and masked_dummy_gammas_2 are homomorphically
922   // computed from commit_as.
923   ASSIGN_OR_RETURN(
924       PedersenOverZn::Commitment masked_dummy_commit_alphas_2,
925       pedersen_->CommitWithRand(zero_vector, masked_dummy_alphas_opening_2));
926   ASSIGN_OR_RETURN(
927       PedersenOverZn::Commitment masked_dummy_commit_gammas_2,
928       pedersen_->CommitWithRand(zero_vector, masked_dummy_gammas_opening_2));
929   for (size_t i = 0; i < commit_as.size(); ++i) {
930     masked_dummy_commit_alphas_2 = pedersen_->Add(
931         pedersen_->Multiply(commit_as[i], masked_dummy_messages[i]),
932         masked_dummy_commit_alphas_2);
933     masked_dummy_commit_gammas_2 =
934         pedersen_->Add(pedersen_->Multiply(commit_as[i], masked_dummy_rs[i]),
935                        masked_dummy_commit_gammas_2);
936   }
937 
938   // Compute the masked_dummy_encrypted_masked_messages homomorphically.
939   std::vector<BigNum> dummy_masked_encrypted_masked_messages;
940   dummy_masked_encrypted_masked_messages.reserve(masked_dummy_messages.size());
941   for (size_t i = 0; i < masked_dummy_messages.size(); ++i) {
942     dummy_masked_encrypted_masked_messages.push_back(
943         masked_dummy_alphas[i] + masked_dummy_bs[i] * ec_group_->GetOrder());
944   }
945 
946   std::vector<CamenischShoupCiphertext> parsed_encrypted_k;
947   parsed_encrypted_k.reserve(
948       public_camenisch_shoup_->vector_encryption_length());
949   std::vector<CamenischShoupCiphertext> parsed_encrypted_y;
950   parsed_encrypted_y.reserve(
951       public_camenisch_shoup_->vector_encryption_length());
952 
953   for (size_t i = 0; i < public_camenisch_shoup_->vector_encryption_length();
954        ++i) {
955     ASSIGN_OR_RETURN(CamenischShoupCiphertext cs_encrypt_k_at_i,
956                      public_camenisch_shoup_->ParseCiphertextProto(
957                          public_key.encrypted_k(i)));
958     parsed_encrypted_k.push_back(std::move(cs_encrypt_k_at_i));
959 
960     ASSIGN_OR_RETURN(CamenischShoupCiphertext cs_encrypt_y_at_i,
961                      public_camenisch_shoup_->ParseCiphertextProto(
962                          public_key.encrypted_y(i)));
963     parsed_encrypted_y.push_back(std::move(cs_encrypt_y_at_i));
964   }
965 
966   // Generate the dummy Camenisch Shoup encryptions.
967   ASSIGN_OR_RETURN(
968       std::vector<CamenischShoupCiphertext>
969           masked_dummy_encrypted_masked_messages,
970       GenerateHomomorphicCsCiphertexts(
971           dummy_masked_encrypted_masked_messages, masked_dummy_as,
972           masked_dummy_gammas, masked_dummy_encryption_randomness,
973           parsed_encrypted_k, parsed_encrypted_y, public_camenisch_shoup_));
974 
975   //  Recreate dummy composites from masked dummy composites (in order to
976   //  regenerate Proof Message 1). Each dummy_composite is computed as
977   //  masked_dummy_composite / original_value^challenge_in_proof.
978 
979   ASSIGN_OR_RETURN(BigNum commit_messages_to_challenge_inverse,
980                    pedersen_->Multiply(commit_messages, challenge_from_proof)
981                        .ModInverse(pedersen_->n()));
982   PedersenOverZn::Commitment dummy_commit_messages = pedersen_->Add(
983       masked_dummy_commit_messages, commit_messages_to_challenge_inverse);
984 
985   ASSIGN_OR_RETURN(BigNum commit_rs_to_challenge_inverse,
986                    pedersen_->Multiply(commit_rs, challenge_from_proof)
987                        .ModInverse(pedersen_->n()));
988   PedersenOverZn::Commitment dummy_commit_rs =
989       pedersen_->Add(masked_dummy_commit_rs, commit_rs_to_challenge_inverse);
990 
991   std::vector<PedersenOverZn::Commitment> dummy_commit_as;
992   dummy_commit_as.reserve(commit_as.size());
993   for (size_t i = 0; i < commit_as.size(); ++i) {
994     ASSIGN_OR_RETURN(BigNum commit_as_to_challenge_inverse,
995                      pedersen_->Multiply(commit_as[i], challenge_from_proof)
996                          .ModInverse(pedersen_->n()));
997     dummy_commit_as.push_back(pedersen_->Add(masked_dummy_commit_as[i],
998                                              commit_as_to_challenge_inverse));
999   }
1000 
1001   ASSIGN_OR_RETURN(BigNum commit_bs_to_challenge_inverse,
1002                    pedersen_->Multiply(commit_bs, challenge_from_proof)
1003                        .ModInverse(pedersen_->n()));
1004   PedersenOverZn::Commitment dummy_commit_bs =
1005       pedersen_->Add(masked_dummy_commit_bs, commit_bs_to_challenge_inverse);
1006 
1007   ASSIGN_OR_RETURN(BigNum commit_alphas_to_challenge_inverse,
1008                    pedersen_->Multiply(commit_alphas, challenge_from_proof)
1009                        .ModInverse(pedersen_->n()));
1010   PedersenOverZn::Commitment dummy_commit_alphas_1 = pedersen_->Add(
1011       masked_dummy_commit_alphas_1, commit_alphas_to_challenge_inverse);
1012   PedersenOverZn::Commitment dummy_commit_alphas_2 = pedersen_->Add(
1013       masked_dummy_commit_alphas_2, commit_alphas_to_challenge_inverse);
1014 
1015   ASSIGN_OR_RETURN(BigNum commit_gammas_to_challenge_inverse,
1016                    pedersen_->Multiply(commit_gammas, challenge_from_proof)
1017                        .ModInverse(pedersen_->n()));
1018   PedersenOverZn::Commitment dummy_commit_gammas_1 = pedersen_->Add(
1019       masked_dummy_commit_gammas_1, commit_gammas_to_challenge_inverse);
1020   PedersenOverZn::Commitment dummy_commit_gammas_2 = pedersen_->Add(
1021       masked_dummy_commit_gammas_2, commit_gammas_to_challenge_inverse);
1022 
1023   // Package dummy_composites into Proof message_1.
1024   proto::BbObliviousSignatureRequestProof::Message1 message_1;
1025   message_1.set_dummy_commit_messages(dummy_commit_messages.ToBytes());
1026   message_1.set_dummy_commit_rs(dummy_commit_rs.ToBytes());
1027   *message_1.mutable_dummy_commit_as() = BigNumVectorToProto(dummy_commit_as);
1028   message_1.set_dummy_commit_bs(dummy_commit_bs.ToBytes());
1029   message_1.set_dummy_commit_alphas_1(dummy_commit_alphas_1.ToBytes());
1030   message_1.set_dummy_commit_alphas_2(dummy_commit_alphas_2.ToBytes());
1031   message_1.set_dummy_commit_gammas_1(dummy_commit_gammas_1.ToBytes());
1032   message_1.set_dummy_commit_gammas_2(dummy_commit_gammas_2.ToBytes());
1033   // dummy_encrypted_masked_messages are computed below.
1034 
1035   // Some extra work is needed for the Camenisch Shoup ciphertext since it
1036   // doesn't natively support inverse.
1037   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
1038     CamenischShoupCiphertext encrypted_masked_messages_to_challenge =
1039         public_camenisch_shoup_->Multiply(encrypted_masked_messages[i],
1040                                           challenge_from_proof);
1041     ASSIGN_OR_RETURN(BigNum encrypted_masked_messages_to_challenge_u_inverse,
1042                      encrypted_masked_messages_to_challenge.u.ModInverse(
1043                          public_camenisch_shoup_->modulus()));
1044     std::vector<BigNum> encrypted_masked_messages_to_challenge_es_inverse;
1045     encrypted_masked_messages_to_challenge_es_inverse.reserve(
1046         encrypted_masked_messages_to_challenge.es.size());
1047     for (size_t i = 0; i < encrypted_masked_messages_to_challenge.es.size();
1048          ++i) {
1049       ASSIGN_OR_RETURN(BigNum encrypted_masked_messages_to_challenge_e_inverse,
1050                        encrypted_masked_messages_to_challenge.es[i].ModInverse(
1051                            public_camenisch_shoup_->modulus()));
1052       encrypted_masked_messages_to_challenge_es_inverse.push_back(
1053           std::move(encrypted_masked_messages_to_challenge_e_inverse));
1054     }
1055     CamenischShoupCiphertext encrypted_masked_messages_to_challenge_inverse{
1056         std::move(encrypted_masked_messages_to_challenge_u_inverse),
1057         std::move(encrypted_masked_messages_to_challenge_es_inverse)};
1058     CamenischShoupCiphertext dummy_encrypted_masked_messages =
1059         public_camenisch_shoup_->Add(
1060             masked_dummy_encrypted_masked_messages[i],
1061             encrypted_masked_messages_to_challenge_inverse);
1062 
1063     *message_1.add_repeated_dummy_encrypted_masked_messages() =
1064         CamenischShoupCiphertextToProto(dummy_encrypted_masked_messages);
1065   }
1066 
1067   // Reconstruct the challenge and check that it matches the one supplied in
1068   // the proof.
1069   ASSIGN_OR_RETURN(BigNum reconstructed_challenge,
1070                    GenerateRequestProofChallenge(proof_statement, message_1));
1071 
1072   if (reconstructed_challenge != challenge_from_proof) {
1073     return absl::InvalidArgumentError(
1074         absl::StrCat("BbObliviousSignature::VerifyRequest: Failed to verify "
1075                      "request proof. Challenge in proof (",
1076                      challenge_from_proof.ToDecimalString(),
1077                      ") does not match reconstructed challenge (",
1078                      reconstructed_challenge.ToDecimalString(), ")."));
1079   }
1080 
1081   return absl::OkStatus();
1082 }
1083 
1084 StatusOr<std::tuple<proto::BbObliviousSignatureResponse,
1085                     proto::BbObliviousSignatureResponseProof>>
GenerateResponseAndProof(const proto::BbObliviousSignatureRequest & request,const proto::BbObliviousSignaturePublicKey & public_key,const proto::BbObliviousSignaturePrivateKey & private_key,const PedersenOverZn::Commitment & commit_messages,const PedersenOverZn::Commitment & commit_rs,PrivateCamenischShoup * private_camenisch_shoup)1086 BbObliviousSignature::GenerateResponseAndProof(
1087     const proto::BbObliviousSignatureRequest& request,
1088     const proto::BbObliviousSignaturePublicKey& public_key,
1089     const proto::BbObliviousSignaturePrivateKey& private_key,
1090     const PedersenOverZn::Commitment& commit_messages,
1091     const PedersenOverZn::Commitment& commit_rs,
1092     PrivateCamenischShoup* private_camenisch_shoup) {
1093   proto::BbObliviousSignatureResponse response_proto;
1094   proto::BbObliviousSignatureResponseProof response_proof_proto;
1095 
1096   if (request.num_messages() > pedersen_->gs().size() ||
1097       request.num_messages() < 0) {
1098     return absl::InvalidArgumentError(
1099         "BbObliviousSignature::GenerateResponse: invalid num_messages in "
1100         "request.");
1101   }
1102 
1103   size_t num_camenisch_shoup_ciphertexts =
1104       request.repeated_encrypted_masked_messages_size();
1105 
1106   // We will refer to the values decrypted from the CS ciphertexts as betas.
1107   // These betas are implicitly bounded as long as the request proof was
1108   // verified (and the sender generated its parameters correctly).
1109   std::vector<BigNum> betas;
1110   betas.reserve(request.num_messages());
1111   std::vector<CamenischShoupCiphertext> encrypted_masked_messages;
1112   encrypted_masked_messages.reserve(num_camenisch_shoup_ciphertexts);
1113   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
1114     ASSIGN_OR_RETURN(CamenischShoupCiphertext encrypted_masked_messages_at_i,
1115                      public_camenisch_shoup_->ParseCiphertextProto(
1116                          request.repeated_encrypted_masked_messages(i)));
1117     ASSIGN_OR_RETURN(
1118         std::vector<BigNum> betas_at_i,
1119         private_camenisch_shoup->Decrypt(encrypted_masked_messages_at_i));
1120 
1121     encrypted_masked_messages.push_back(
1122         std::move(encrypted_masked_messages_at_i));
1123     betas.insert(betas.end(), std::make_move_iterator(betas_at_i.begin()),
1124                  std::make_move_iterator(betas_at_i.end()));
1125   }
1126   // Truncate the last few elements of betas, if it's larger than
1127   // num_messages. (These should be all zeros.)
1128   betas.erase(betas.begin() + request.num_messages(), betas.end());
1129 
1130   std::vector<ECPoint> masked_prf_values;
1131   masked_prf_values.reserve(request.num_messages());
1132   for (uint64_t i = 0; i < request.num_messages(); ++i) {
1133     ASSIGN_OR_RETURN(BigNum beta_inverse,
1134                      betas[i].ModInverse(ec_group_->GetOrder()));
1135     ASSIGN_OR_RETURN(ECPoint masked_prf_value, base_g_.Mul(beta_inverse));
1136     masked_prf_values.push_back(std::move(masked_prf_value));
1137   }
1138 
1139   ASSIGN_OR_RETURN(*response_proto.mutable_masked_signature_values(),
1140                    ECPointVectorToProto(masked_prf_values));
1141 
1142   // Commit to decrypted_values (aka betas)
1143   ASSIGN_OR_RETURN(auto commit_and_open_betas, pedersen_->Commit(betas));
1144   response_proof_proto.set_commit_betas(
1145       commit_and_open_betas.commitment.ToBytes());
1146 
1147   // (1) Generate Proof Message 1
1148 
1149   // (1.1) Create dummy_betas, dummy_xs and dummy commitment-opening.
1150   // beta is bounded by 2^(challenge_length + security+parameter) * q^3, so
1151   // dummy_beta is bounded by the beta bound plus an additional
1152   // 2^(challenge_length + security_parameter).
1153   BigNum dummy_betas_bound =
1154       ctx_->One()
1155           .Lshift(2 * parameters_proto_.challenge_length_bits() +
1156                   2 * parameters_proto_.security_parameter())
1157           .Mul(ec_group_->GetOrder())
1158           .Mul(ec_group_->GetOrder())
1159           .Mul(ec_group_->GetOrder());
1160   std::vector<BigNum> dummy_betas;
1161   dummy_betas.reserve(request.num_messages());
1162   for (uint64_t i = 0; i < request.num_messages(); ++i) {
1163     dummy_betas.push_back(ctx_->GenerateRandLessThan(dummy_betas_bound));
1164   }
1165 
1166   std::vector<BigNum> dummy_xs;
1167   dummy_xs.reserve(public_camenisch_shoup_->vector_encryption_length());
1168   BigNum dummy_xs_bound = public_camenisch_shoup_->n().Lshift(
1169       parameters_proto_.challenge_length_bits() +
1170       parameters_proto_.security_parameter());
1171   for (uint64_t i = 0; i < public_camenisch_shoup_->vector_encryption_length();
1172        ++i) {
1173     dummy_xs.push_back(ctx_->GenerateRandLessThan(dummy_xs_bound));
1174   }
1175 
1176   // Dummy opening has the same size as dummy_xs.
1177   BigNum dummy_beta_opening = ctx_->GenerateRandLessThan(dummy_xs_bound);
1178   ASSIGN_OR_RETURN(PedersenOverZn::Commitment dummy_commit_betas,
1179                    pedersen_->CommitWithRand(dummy_betas, dummy_beta_opening));
1180 
1181   // (1.2) Use the dummy values above to create dummy_cs_ys,
1182   // dummy_commit_betas, and dummy_base_gs and add them to proof message 1.
1183   std::vector<BigNum> dummy_cs_ys;
1184   dummy_cs_ys.reserve(public_camenisch_shoup_->vector_encryption_length());
1185   for (uint64_t i = 0; i < public_camenisch_shoup_->vector_encryption_length();
1186        ++i) {
1187     dummy_cs_ys.push_back(private_camenisch_shoup->g().ModExp(
1188         dummy_xs[i], private_camenisch_shoup->modulus()));
1189   }
1190 
1191   std::vector<ECPoint> dummy_base_gs;
1192   dummy_base_gs.reserve(request.num_messages());
1193   for (uint64_t i = 0; i < request.num_messages(); ++i) {
1194     ASSIGN_OR_RETURN(ECPoint dummy_base_g,
1195                      masked_prf_values[i].Mul(dummy_betas[i]));
1196     dummy_base_gs.push_back(std::move(dummy_base_g));
1197   }
1198 
1199   proto::BbObliviousSignatureResponseProof::Message1 proof_message_1;
1200   *proof_message_1.mutable_dummy_camenisch_shoup_ys() =
1201       BigNumVectorToProto(dummy_cs_ys);
1202   proof_message_1.set_dummy_commit_betas(dummy_commit_betas.ToBytes());
1203   ASSIGN_OR_RETURN(*proof_message_1.mutable_dummy_base_gs(),
1204                    ECPointVectorToProto(dummy_base_gs));
1205 
1206   // (1.3) dummy_enc_mask_messages_es is more complicated: we need to create one
1207   // entry for each CS ciphertext in the request.
1208   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
1209     size_t batch_start_index =
1210         i * public_camenisch_shoup_->vector_encryption_length();
1211     size_t batch_size =
1212         std::min(public_camenisch_shoup_->vector_encryption_length(),
1213                  request.num_messages() - batch_start_index);
1214     size_t batch_end_index = batch_start_index + batch_size;
1215 
1216     // determine the dummy_betas that are to be used for this ciphertext.
1217     std::vector<BigNum> dummy_betas_for_batch(
1218         dummy_betas.begin() + batch_start_index,
1219         dummy_betas.begin() + batch_end_index);
1220 
1221     //  intermediate_es contains
1222     // (1+n)^dummy_betas[i] mod n^(s+1) in the "es" component. This is achieved
1223     // by encrypting dummy_betas with randomness 0.
1224     ASSIGN_OR_RETURN(CamenischShoupCiphertext intermediate_ciphertext,
1225                      private_camenisch_shoup->EncryptWithRand(
1226                          dummy_betas_for_batch, ctx_->Zero()));
1227     // dummy_enc_mask_messages_es contains u^dummy_xs[j] * (1+n)^dummy_betas[j]
1228     // mod n^(s+1) in the "es" component.
1229     std::vector<BigNum> dummy_enc_mask_messages_es;
1230     dummy_enc_mask_messages_es.reserve(
1231         public_camenisch_shoup_->vector_encryption_length());
1232     for (size_t j = 0; j < batch_size; ++j) {
1233       BigNum dummy_e =
1234           encrypted_masked_messages[i]
1235               .u.ModExp(dummy_xs[j], private_camenisch_shoup->modulus())
1236               .ModMul(intermediate_ciphertext.es[j],
1237                       private_camenisch_shoup->modulus());
1238       dummy_enc_mask_messages_es.push_back(std::move(dummy_e));
1239     }
1240 
1241     *proof_message_1.add_repeated_dummy_encrypted_masked_messages_es() =
1242         BigNumVectorToProto(dummy_enc_mask_messages_es);
1243   }
1244 
1245   // (2) Generate challenge
1246   ASSIGN_OR_RETURN(
1247       BigNum challenge,
1248       GenerateResponseProofChallenge(
1249           public_key, commit_messages, commit_rs, request, response_proto,
1250           commit_and_open_betas.commitment, proof_message_1));
1251   response_proof_proto.set_challenge(challenge.ToBytes());
1252 
1253   // (3) Generate Message 2
1254   // Compute all masked dummy values: masked_dummy_betas,
1255   // masked_dummy_xs, masked_dummy_beta_opening
1256   std::vector<BigNum> masked_dummy_betas;
1257   masked_dummy_betas.reserve(request.num_messages());
1258   for (uint64_t i = 0; i < request.num_messages(); ++i) {
1259     masked_dummy_betas.push_back(dummy_betas[i] + betas[i].Mul(challenge));
1260   }
1261   std::vector<BigNum> masked_dummy_xs;
1262   masked_dummy_xs.reserve(public_camenisch_shoup_->vector_encryption_length());
1263   for (uint64_t i = 0; i < public_camenisch_shoup_->vector_encryption_length();
1264        ++i) {
1265     masked_dummy_xs.push_back(
1266         dummy_xs[i] + (private_camenisch_shoup->xs()[i].Mul(challenge)));
1267   }
1268   BigNum masked_dummy_beta_opening =
1269       dummy_beta_opening + commit_and_open_betas.opening.Mul(challenge);
1270 
1271   proto::BbObliviousSignatureResponseProof::Message2* response_proof_message_2 =
1272       response_proof_proto.mutable_message_2();
1273   *response_proof_message_2->mutable_masked_dummy_betas() =
1274       BigNumVectorToProto(masked_dummy_betas);
1275   *response_proof_message_2->mutable_masked_dummy_camenisch_shoup_xs() =
1276       BigNumVectorToProto(masked_dummy_xs);
1277   response_proof_message_2->set_masked_dummy_beta_opening(
1278       masked_dummy_beta_opening.ToBytes());
1279 
1280   return std::make_tuple(response_proto, response_proof_proto);
1281 }
1282 
VerifyResponse(const proto::BbObliviousSignaturePublicKey & public_key,const proto::BbObliviousSignatureResponse & response,const proto::BbObliviousSignatureResponseProof & response_proof,const proto::BbObliviousSignatureRequest & request,const PedersenOverZn::Commitment & commit_messages,const PedersenOverZn::Commitment & commit_rs)1283 Status BbObliviousSignature::VerifyResponse(
1284     const proto::BbObliviousSignaturePublicKey& public_key,
1285     const proto::BbObliviousSignatureResponse& response,
1286     const proto::BbObliviousSignatureResponseProof& response_proof,
1287     const proto::BbObliviousSignatureRequest& request,
1288     const PedersenOverZn::Commitment& commit_messages,
1289     const PedersenOverZn::Commitment& commit_rs) {
1290   if (response.masked_signature_values().serialized_ec_points_size() !=
1291       request.num_messages()) {
1292     return absl::InvalidArgumentError(
1293         "BbObliviousSignature::VerifyResponse: response has a different "
1294         "number "
1295         "of masked_signature_values values than the request");
1296   }
1297 
1298   if (response_proof.message_2()
1299           .masked_dummy_camenisch_shoup_xs()
1300           .serialized_big_nums_size() !=
1301       public_camenisch_shoup_->vector_encryption_length()) {
1302     return absl::InvalidArgumentError(
1303         "BbObliviousSignature::VerifyResponse: response proof has wrong "
1304         "number "
1305         "of masked_dummy_camenisch_shoup_xs in message 2.");
1306   }
1307   if (response_proof.message_2()
1308           .masked_dummy_betas()
1309           .serialized_big_nums_size() != request.num_messages()) {
1310     return absl::InvalidArgumentError(
1311         "BbObliviousSignature::VerifyResponse: response proof has wrong "
1312         "number "
1313         "of masked_dummy_betas in message 2.");
1314   }
1315 
1316   size_t num_camenisch_shoup_ciphertexts =
1317       request.repeated_encrypted_masked_messages_size();
1318 
1319   std::vector<CamenischShoupCiphertext> encrypted_masked_messages;
1320   encrypted_masked_messages.reserve(num_camenisch_shoup_ciphertexts);
1321   // Parse the needed request, response and response proof elements.
1322   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
1323     ASSIGN_OR_RETURN(CamenischShoupCiphertext encrypted_masked_messages_at_i,
1324                      public_camenisch_shoup_->ParseCiphertextProto(
1325                          request.repeated_encrypted_masked_messages(i)));
1326     encrypted_masked_messages.push_back(
1327         std::move(encrypted_masked_messages_at_i));
1328   }
1329   ASSIGN_OR_RETURN(std::vector<ECPoint> masked_signature_values,
1330                    ParseECPointVectorProto(ctx_, ec_group_,
1331                                            response.masked_signature_values()));
1332   PedersenOverZn::Commitment commit_betas =
1333       ctx_->CreateBigNum(response_proof.commit_betas());
1334   BigNum challenge_from_proof = ctx_->CreateBigNum(response_proof.challenge());
1335   std::vector<BigNum> masked_dummy_camenisch_shoup_xs = ParseBigNumVectorProto(
1336       ctx_, response_proof.message_2().masked_dummy_camenisch_shoup_xs());
1337   std::vector<BigNum> masked_dummy_betas = ParseBigNumVectorProto(
1338       ctx_, response_proof.message_2().masked_dummy_betas());
1339   BigNum masked_dummy_beta_opening = ctx_->CreateBigNum(
1340       response_proof.message_2().masked_dummy_beta_opening());
1341 
1342   // Check the lengths of masked dummy betas
1343   BigNum masked_dummy_betas_bound =
1344       ctx_->One().Lshift(2 * parameters_proto_.challenge_length_bits() +
1345                          2 * parameters_proto_.security_parameter() + 1) *
1346       ec_group_->GetOrder() * ec_group_->GetOrder() * ec_group_->GetOrder();
1347   for (uint64_t i = 0; i < request.num_messages(); ++i) {
1348     if (masked_dummy_betas[i] >= masked_dummy_betas_bound)
1349       return absl::InvalidArgumentError(absl::StrCat(
1350           "BbObliviousSignature::VerifyResponse: The ", i,
1351           "th entry of masked_dummy_betas,",
1352           masked_dummy_betas[i].ToDecimalString(), " (bit length ",
1353           masked_dummy_betas[i].BitLength(), ")",
1354           ",is larger than the acceptable bound: ",
1355           masked_dummy_betas_bound.ToDecimalString(), " (bit length ",
1356           masked_dummy_betas_bound.BitLength(), ")"));
1357   }
1358 
1359   // Reconstruct each element of Proof message 1.
1360   proto::BbObliviousSignatureResponseProof::Message1 reconstructed_message_1;
1361 
1362   // Reconstruct dummy_base_gs.
1363   std::vector<ECPoint> dummy_base_gs;
1364   dummy_base_gs.reserve(request.num_messages());
1365   ASSIGN_OR_RETURN(ECPoint base_g_to_challenge,
1366                    base_g_.Mul(challenge_from_proof));
1367   ASSIGN_OR_RETURN(ECPoint base_g_to_challenge_inverse,
1368                    base_g_to_challenge.Inverse());
1369   for (uint64_t i = 0; i < request.num_messages(); ++i) {
1370     ASSIGN_OR_RETURN(ECPoint masked_dummy_g,
1371                      masked_signature_values[i].Mul(masked_dummy_betas[i]));
1372     // Compute dummy_base_g as masked_dummy_g / g^c
1373     ASSIGN_OR_RETURN(ECPoint dummy_base_g,
1374                      masked_dummy_g.Add(base_g_to_challenge_inverse));
1375     dummy_base_gs.push_back(std::move(dummy_base_g));
1376   }
1377 
1378   ASSIGN_OR_RETURN(*reconstructed_message_1.mutable_dummy_base_gs(),
1379                    ECPointVectorToProto(dummy_base_gs));
1380 
1381   for (size_t i = 0; i < num_camenisch_shoup_ciphertexts; ++i) {
1382     size_t batch_start_index =
1383         i * public_camenisch_shoup_->vector_encryption_length();
1384     size_t batch_size =
1385         std::min(public_camenisch_shoup_->vector_encryption_length(),
1386                  request.num_messages() - batch_start_index);
1387     size_t batch_end_index = batch_start_index + batch_size;
1388     std::vector<BigNum> masked_dummy_betas_for_batch(
1389         masked_dummy_betas.begin() + batch_start_index,
1390         masked_dummy_betas.begin() + batch_end_index);
1391     // Reconstruct dummy_es
1392     // es[i] of intermediate_ciphertext is (1+n)^masked_dummy_betas[i].
1393     ASSIGN_OR_RETURN(CamenischShoupCiphertext intermediate_ciphertext,
1394                      public_camenisch_shoup_->EncryptWithRand(
1395                          masked_dummy_betas_for_batch, ctx_->Zero()));
1396     std::vector<BigNum> dummy_es;
1397     dummy_es.reserve(batch_size);
1398     for (size_t j = 0; j < batch_size; ++j) {
1399       // masked_dummy_e = (1+n)^masked_dummy_betas_for_batch[j] *
1400       // u^masked_dummy_xs[j]
1401       BigNum masked_dummy_e = intermediate_ciphertext.es[j].ModMul(
1402           encrypted_masked_messages[i].u.ModExp(
1403               masked_dummy_camenisch_shoup_xs[j],
1404               public_camenisch_shoup_->modulus()),
1405           public_camenisch_shoup_->modulus());
1406 
1407       ASSIGN_OR_RETURN(
1408           BigNum e_to_challenge_inverse,
1409           encrypted_masked_messages[i]
1410               .es[j]
1411               .ModExp(challenge_from_proof, public_camenisch_shoup_->modulus())
1412               .ModInverse(public_camenisch_shoup_->modulus()));
1413 
1414       BigNum dummy_e = masked_dummy_e.ModMul(
1415           e_to_challenge_inverse, public_camenisch_shoup_->modulus());
1416       dummy_es.push_back(std::move(dummy_e));
1417     }
1418     *reconstructed_message_1.add_repeated_dummy_encrypted_masked_messages_es() =
1419         BigNumVectorToProto(dummy_es);
1420   }
1421 
1422   // Reconstruct dummy_commit_betas.
1423   ASSIGN_OR_RETURN(
1424       PedersenOverZn::Commitment masked_dummy_commit_betas,
1425       pedersen_->CommitWithRand(masked_dummy_betas, masked_dummy_beta_opening));
1426   ASSIGN_OR_RETURN(BigNum commit_betas_to_challenge_inverse,
1427                    pedersen_->Multiply(commit_betas, challenge_from_proof)
1428                        .ModInverse(pedersen_->n()));
1429   PedersenOverZn::Commitment dummy_commit_betas = pedersen_->Add(
1430       masked_dummy_commit_betas, commit_betas_to_challenge_inverse);
1431   reconstructed_message_1.set_dummy_commit_betas(dummy_commit_betas.ToBytes());
1432 
1433   // Reconstruct dummy_camenisch_shoup_ys
1434   std::vector<BigNum> dummy_camenisch_shoup_ys;
1435   dummy_camenisch_shoup_ys.reserve(
1436       public_camenisch_shoup_->vector_encryption_length());
1437   for (uint64_t i = 0; i < public_camenisch_shoup_->vector_encryption_length();
1438        ++i) {
1439     BigNum masked_dummy_y = public_camenisch_shoup_->g().ModExp(
1440         masked_dummy_camenisch_shoup_xs[i], public_camenisch_shoup_->modulus());
1441     ASSIGN_OR_RETURN(
1442         BigNum y_to_challenge_inverse,
1443         public_camenisch_shoup_->ys()[i]
1444             .ModExp(challenge_from_proof, public_camenisch_shoup_->modulus())
1445             .ModInverse(public_camenisch_shoup_->modulus()));
1446     BigNum dummy_camenisch_shoup_y = masked_dummy_y.ModMul(
1447         y_to_challenge_inverse, public_camenisch_shoup_->modulus());
1448     dummy_camenisch_shoup_ys.push_back(std::move(dummy_camenisch_shoup_y));
1449   }
1450   *reconstructed_message_1.mutable_dummy_camenisch_shoup_ys() =
1451       BigNumVectorToProto(dummy_camenisch_shoup_ys);
1452 
1453   // Reconstruct the challenge by applying FiatShamir to the reconstructed
1454   // first message, and ensure it exactly matches the challenge in the proof.
1455   ASSIGN_OR_RETURN(BigNum reconstructed_challenge,
1456                    GenerateResponseProofChallenge(
1457                        public_key, commit_messages, commit_rs, request,
1458                        response, commit_betas, reconstructed_message_1));
1459 
1460   if (reconstructed_challenge != challenge_from_proof) {
1461     return absl::InvalidArgumentError(
1462         absl::StrCat("BbObliviousSignature::VerifyResponse: Failed to verify "
1463                      "response proof. Challenge in proof (",
1464                      challenge_from_proof.ToDecimalString(),
1465                      ") does not match reconstructed challenge (",
1466                      reconstructed_challenge.ToDecimalString(), ")."));
1467   }
1468   return absl::OkStatus();
1469 }
1470 
ExtractResults(const proto::BbObliviousSignatureResponse & response,const proto::BbObliviousSignatureRequest & request,const proto::BbObliviousSignatureRequestPrivateState & request_state)1471 StatusOr<std::vector<ECPoint>> BbObliviousSignature::ExtractResults(
1472     const proto::BbObliviousSignatureResponse& response,
1473     const proto::BbObliviousSignatureRequest& request,
1474     const proto::BbObliviousSignatureRequestPrivateState& request_state) {
1475   // Unmask and extract the signatures.
1476   ASSIGN_OR_RETURN(std::vector<ECPoint> masked_prf_values,
1477                    ParseECPointVectorProto(ctx_, ec_group_,
1478                                            response.masked_signature_values()));
1479   std::vector<BigNum> as =
1480       ParseBigNumVectorProto(ctx_, request_state.private_as());
1481 
1482   std::vector<ECPoint> prf_values;
1483   prf_values.reserve(masked_prf_values.size());
1484 
1485   for (size_t i = 0; i < masked_prf_values.size(); ++i) {
1486     ASSIGN_OR_RETURN(ECPoint prf_value, masked_prf_values[i].Mul(as[i]));
1487     prf_values.push_back(std::move(prf_value));
1488   }
1489 
1490   return std::move(prf_values);
1491 }
1492 
1493 // Generates the challenge for the Request proof using the Fiat-Shamir
1494 // heuristic.
GenerateRequestProofChallenge(const proto::BbObliviousSignatureRequestProof::Statement & proof_statement,const proto::BbObliviousSignatureRequestProof::Message1 & proof_message_1)1495 StatusOr<BigNum> BbObliviousSignature::GenerateRequestProofChallenge(
1496     const proto::BbObliviousSignatureRequestProof::Statement& proof_statement,
1497     const proto::BbObliviousSignatureRequestProof::Message1& proof_message_1) {
1498   BigNum challenge_bound =
1499       ctx_->One().Lshift(parameters_proto_.challenge_length_bits());
1500 
1501   // Note that the random oracle prefix is implicitly included as part of the
1502   // parameters being serialized in the statement proto. We skip including it
1503   // again here to avoid unnecessary duplication.
1504   std::string challenge_string =
1505       "BbObliviousSignature::GenerateResponseProofChallenge";
1506 
1507   auto challenge_sos =
1508       std::make_unique<google::protobuf::io::StringOutputStream>(
1509           &challenge_string);
1510   auto challenge_cos =
1511       std::make_unique<google::protobuf::io::CodedOutputStream>(
1512           challenge_sos.get());
1513   challenge_cos->SetSerializationDeterministic(true);
1514   challenge_cos->WriteVarint64(proof_statement.ByteSizeLong());
1515   challenge_cos->WriteString(SerializeAsStringInOrder(proof_statement));
1516 
1517   challenge_cos->WriteVarint64(proof_message_1.ByteSizeLong());
1518   challenge_cos->WriteString(SerializeAsStringInOrder(proof_message_1));
1519 
1520   // Delete the CodedOutputStream and StringOutputStream to make sure they are
1521   // cleaned up before hashing.
1522   challenge_cos.reset();
1523   challenge_sos.reset();
1524 
1525   return ctx_->RandomOracleSha512(challenge_string, challenge_bound);
1526 }
1527 
1528 // Generates the challenge for the Response proof using the Fiat-Shamir
1529 // heuristic.
GenerateResponseProofChallenge(const proto::BbObliviousSignaturePublicKey & public_key,const PedersenOverZn::Commitment & commit_messages,const PedersenOverZn::Commitment & commit_rs,const proto::BbObliviousSignatureRequest & request,const proto::BbObliviousSignatureResponse & response,const PedersenOverZn::Commitment & commit_betas,const proto::BbObliviousSignatureResponseProof::Message1 & proof_message_1)1530 StatusOr<BigNum> BbObliviousSignature::GenerateResponseProofChallenge(
1531     const proto::BbObliviousSignaturePublicKey& public_key,
1532     const PedersenOverZn::Commitment& commit_messages,
1533     const PedersenOverZn::Commitment& commit_rs,
1534     const proto::BbObliviousSignatureRequest& request,
1535     const proto::BbObliviousSignatureResponse& response,
1536     const PedersenOverZn::Commitment& commit_betas,
1537     const proto::BbObliviousSignatureResponseProof::Message1& proof_message_1) {
1538   BigNum challenge_bound =
1539       ctx_->One().Lshift(parameters_proto_.challenge_length_bits());
1540 
1541   // Generate the statement
1542   proto::BbObliviousSignatureResponseProof::Statement statement;
1543   *statement.mutable_parameters() = parameters_proto_;
1544   *statement.mutable_public_key() = public_key;
1545   statement.set_commit_messages(commit_messages.ToBytes());
1546   statement.set_commit_rs(commit_rs.ToBytes());
1547   *statement.mutable_request() = request;
1548   *statement.mutable_response() = response;
1549   statement.set_commit_betas(commit_betas.ToBytes());
1550 
1551   // Note that the random oracle prefix is implicitly included as part of the
1552   // parameters being serialized in the statement proto. We skip including it
1553   // again here to avoid unnecessary duplication.
1554   std::string challenge_string =
1555       "BbObliviousSignature::GenerateResponseProofChallenge";
1556 
1557   auto challenge_sos =
1558       std::make_unique<google::protobuf::io::StringOutputStream>(
1559           &challenge_string);
1560   auto challenge_cos =
1561       std::make_unique<google::protobuf::io::CodedOutputStream>(
1562           challenge_sos.get());
1563   challenge_cos->SetSerializationDeterministic(true);
1564   challenge_cos->WriteVarint64(statement.ByteSizeLong());
1565   challenge_cos->WriteString(SerializeAsStringInOrder(statement));
1566 
1567   challenge_cos->WriteVarint64(proof_message_1.ByteSizeLong());
1568   challenge_cos->WriteString(SerializeAsStringInOrder(proof_message_1));
1569 
1570   // Delete the CodedOutputStream and StringOutputStream to make sure they are
1571   // cleaned up before hashing.
1572   challenge_cos.reset();
1573   challenge_sos.reset();
1574 
1575   return ctx_->RandomOracleSha512(challenge_string, challenge_bound);
1576 }
1577 
1578 }  // namespace private_join_and_compute
1579