• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 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 "act/act_v0/act_v0.h"
17 
18 #include <memory>
19 #include <string>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 
24 // ANDROID: Not sure how upstream worked without this header
25 #include <absl/strings/str_cat.h>
26 
27 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
28 #include "act/act.pb.h"
29 #include "act/act_v0/act_v0.pb.h"
30 #include "private_join_and_compute/crypto/big_num.h"
31 #include "private_join_and_compute/crypto/camenisch_shoup.h"
32 #include "private_join_and_compute/crypto/context.h"
33 #include "private_join_and_compute/crypto/dodis_yampolskiy_prf/bb_oblivious_signature.h"
34 #include "private_join_and_compute/crypto/dodis_yampolskiy_prf/bb_oblivious_signature.pb.h"
35 #include "private_join_and_compute/crypto/dodis_yampolskiy_prf/dy_verifiable_random_function.h"
36 #include "private_join_and_compute/crypto/dodis_yampolskiy_prf/dy_verifiable_random_function.pb.h"
37 #include "private_join_and_compute/crypto/ec_group.h"
38 #include "private_join_and_compute/crypto/ec_point.h"
39 #include "private_join_and_compute/crypto/pedersen_over_zn.h"
40 #include "private_join_and_compute/crypto/proto/ec_point.pb.h"
41 #include "private_join_and_compute/crypto/proto/proto_util.h"
42 
43 namespace private_join_and_compute {
44 namespace anonymous_counting_tokens {
45 
46 namespace {
47 
CreateBbObliviousSignature(const SchemeParametersV0 & scheme_parameters_v0,const ServerPublicParametersV0 & server_public_parameters_v0,Context * ctx,ECGroup * ec_group,PedersenOverZn * pedersen,PublicCamenischShoup * public_camenisch_shoup)48 StatusOr<std::unique_ptr<BbObliviousSignature>> CreateBbObliviousSignature(
49     const SchemeParametersV0& scheme_parameters_v0,
50     const ServerPublicParametersV0& server_public_parameters_v0, Context* ctx,
51     ECGroup* ec_group, PedersenOverZn* pedersen,
52     PublicCamenischShoup* public_camenisch_shoup) {
53   proto::BbObliviousSignatureParameters bb_oblivious_signature_parameters;
54   bb_oblivious_signature_parameters.set_challenge_length_bits(
55       scheme_parameters_v0.challenge_length_bits());
56   bb_oblivious_signature_parameters.set_security_parameter(
57       scheme_parameters_v0.security_parameter());
58   bb_oblivious_signature_parameters.set_random_oracle_prefix(
59       scheme_parameters_v0.random_oracle_prefix());
60   bb_oblivious_signature_parameters.set_base_g(
61       server_public_parameters_v0.prf_base_g());
62   *bb_oblivious_signature_parameters.mutable_pedersen_parameters() =
63       server_public_parameters_v0.pedersen_parameters();
64   *bb_oblivious_signature_parameters.mutable_camenisch_shoup_public_key() =
65       server_public_parameters_v0.camenisch_shoup_public_key();
66 
67   return BbObliviousSignature::Create(
68       std::move(bb_oblivious_signature_parameters), ctx, ec_group,
69       public_camenisch_shoup, pedersen);
70 }
71 
CreateDyVrf(const SchemeParametersV0 & scheme_parameters_v0,const ServerPublicParametersV0 & server_public_parameters_v0,Context * ctx,ECGroup * ec_group,PedersenOverZn * pedersen)72 StatusOr<std::unique_ptr<DyVerifiableRandomFunction>> CreateDyVrf(
73     const SchemeParametersV0& scheme_parameters_v0,
74     const ServerPublicParametersV0& server_public_parameters_v0, Context* ctx,
75     ECGroup* ec_group, PedersenOverZn* pedersen) {
76   proto::DyVrfParameters dy_vrf_parameters;
77   dy_vrf_parameters.set_challenge_length_bits(
78       scheme_parameters_v0.challenge_length_bits());
79   dy_vrf_parameters.set_security_parameter(
80       scheme_parameters_v0.security_parameter());
81   dy_vrf_parameters.set_random_oracle_prefix(
82       scheme_parameters_v0.random_oracle_prefix());
83   dy_vrf_parameters.set_dy_prf_base_g(server_public_parameters_v0.prf_base_g());
84   *dy_vrf_parameters.mutable_pedersen_parameters() =
85       server_public_parameters_v0.pedersen_parameters();
86 
87   return DyVerifiableRandomFunction::Create(std::move(dy_vrf_parameters), ctx,
88                                             ec_group, pedersen);
89 }
90 
91 // Used to generate the client-independent portion of the nonce. A different
92 // nonce is chosen for each element in the batched token request.
GetNoncesForTokenRequest(Context * ctx,const SchemeParameters & scheme_parameters,const ServerPublicParameters & server_public_parameters,const ClientPublicParameters & client_public_parameters,const TokensRequestV0::Part1 & tokens_request_part_1,uint64_t num_messages)93 StatusOr<std::vector<BigNum>> GetNoncesForTokenRequest(
94     Context* ctx, const SchemeParameters& scheme_parameters,
95     const ServerPublicParameters& server_public_parameters,
96     const ClientPublicParameters& client_public_parameters,
97     const TokensRequestV0::Part1& tokens_request_part_1,
98     uint64_t num_messages) {
99   // Parses bit length of the random challenge from scheme parameters.
100   uint64_t challenge_length_bits =
101       scheme_parameters.scheme_parameters_v0().challenge_length_bits();
102   // Computes the upper bound of the challenge and input to the random oracle.
103   BigNum challenge_upper_bound = ctx->One().Lshift(challenge_length_bits);
104 
105   // Note that the random oracle prefix is implicitly included as part of the
106   // parameters being serialized in the statement proto. We skip including it
107   // again here to avoid unnecessary duplication.
108   std::string challenge_string = "GetNoncesForTokenRequest:";
109   auto challenge_sos =
110       std::make_unique<google::protobuf::io::StringOutputStream>(
111           &challenge_string);
112   auto challenge_cos =
113       std::make_unique<google::protobuf::io::CodedOutputStream>(
114           challenge_sos.get());
115   challenge_cos->SetSerializationDeterministic(true);
116   challenge_cos->WriteVarint64(scheme_parameters.ByteSizeLong());
117   challenge_cos->WriteString(SerializeAsStringInOrder(scheme_parameters));
118   challenge_cos->WriteVarint64(server_public_parameters.ByteSizeLong());
119   challenge_cos->WriteString(
120       SerializeAsStringInOrder(server_public_parameters));
121   challenge_cos->WriteVarint64(client_public_parameters.ByteSizeLong());
122   challenge_cos->WriteString(
123       SerializeAsStringInOrder(client_public_parameters));
124   challenge_cos->WriteVarint64(tokens_request_part_1.ByteSizeLong());
125   challenge_cos->WriteString(SerializeAsStringInOrder(tokens_request_part_1));
126   challenge_cos->WriteVarint64(num_messages);
127 
128   // Delete the serialization objects to make sure they clean up and write.
129   challenge_cos.reset();
130   challenge_sos.reset();
131 
132   std::vector<BigNum> outputs;
133   outputs.reserve(num_messages);
134   for (uint64_t i = 0; i < num_messages; ++i) {
135     std::string random_oracle_input_i = absl::StrCat(challenge_string, ",", i);
136     outputs.push_back(
137         ctx->RandomOracleSha512(random_oracle_input_i, challenge_upper_bound));
138   }
139 
140   return std::move(outputs);
141 }
142 
143 }  // namespace
144 
Create()145 std::unique_ptr<AnonymousCountingTokens> AnonymousCountingTokensV0::Create() {
146   return absl::WrapUnique<AnonymousCountingTokensV0>(
147       new AnonymousCountingTokensV0());
148 }
149 
150 // Returns a fresh set of Server parameters corresponding to these
151 // SchemeParameters. Fails with InvalidArgument if the parameters don't
152 // correspond to ACT v0.
GenerateServerParameters(const SchemeParameters & scheme_parameters)153 StatusOr<ServerParameters> AnonymousCountingTokensV0::GenerateServerParameters(
154     const SchemeParameters& scheme_parameters) {
155   if (!scheme_parameters.has_scheme_parameters_v0()) {
156     return absl::InvalidArgumentError(
157         "AnonymousCountingTokensV0::GenerateServerParameters: supplied "
158         "parameters do not correspond to ACTv0.");
159   }
160 
161   const SchemeParametersV0& scheme_parameters_v0 =
162       scheme_parameters.scheme_parameters_v0();
163 
164   Context ctx;
165   ASSIGN_OR_RETURN(ECGroup ec_group,
166                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
167 
168   // Choose base g.
169   ASSIGN_OR_RETURN(ECPoint dy_prf_base_g, ec_group.GetRandomGenerator());
170 
171   // Generate RSA-Modulus and Camenisch-Shoup encryption key.
172   CamenischShoupKey camenisch_shoup_key = GenerateCamenischShoupKey(
173       &ctx, scheme_parameters_v0.modulus_length_bits(),
174       scheme_parameters_v0.camenisch_shoup_s(),
175       scheme_parameters_v0.vector_encryption_length());
176 
177   BigNum n = camenisch_shoup_key.n;
178 
179   auto camenisch_shoup_public_key = std::make_unique<CamenischShoupPublicKey>(
180       CamenischShoupPublicKey{camenisch_shoup_key.n, camenisch_shoup_key.s,
181                               camenisch_shoup_key.vector_encryption_length,
182                               camenisch_shoup_key.g, camenisch_shoup_key.ys});
183   auto camenisch_shoup_private_key = std::make_unique<CamenischShoupPrivateKey>(
184       CamenischShoupPrivateKey{camenisch_shoup_key.xs});
185 
186   auto public_camenisch_shoup = std::make_unique<PublicCamenischShoup>(
187       &ctx, camenisch_shoup_public_key->n, camenisch_shoup_public_key->s,
188       camenisch_shoup_public_key->g, camenisch_shoup_public_key->ys);
189 
190   // Generate Pedersen Parameters.
191   PedersenOverZn::Parameters pedersen_parameters =
192       PedersenOverZn::GenerateParameters(
193           &ctx, n, scheme_parameters_v0.pedersen_batch_size());
194 
195   ASSIGN_OR_RETURN(
196       std::unique_ptr<PedersenOverZn> pedersen,
197       PedersenOverZn::Create(&ctx, pedersen_parameters.gs,
198                              pedersen_parameters.h, pedersen_parameters.n));
199 
200   ServerParameters server_parameters;
201 
202   ServerPublicParametersV0* server_public_parameters_v0 =
203       server_parameters.mutable_public_parameters()
204           ->mutable_server_public_parameters_v0();
205   ASSIGN_OR_RETURN(*server_public_parameters_v0->mutable_prf_base_g(),
206                    dy_prf_base_g.ToBytesCompressed());
207   *server_public_parameters_v0->mutable_pedersen_parameters() =
208       PedersenOverZn::ParametersToProto(pedersen_parameters);
209   *server_public_parameters_v0->mutable_camenisch_shoup_public_key() =
210       CamenischShoupPublicKeyToProto(*camenisch_shoup_public_key);
211 
212   ServerPrivateParametersV0* server_private_parameters_v0 =
213       server_parameters.mutable_private_parameters()
214           ->mutable_server_private_parameters_v0();
215   *server_private_parameters_v0->mutable_camenisch_shoup_private_key() =
216       CamenischShoupPrivateKeyToProto(*camenisch_shoup_private_key);
217 
218   // Generate Boneh-Boyen Oblivious Signature object. This call is safe even
219   // with the partially-ready server_public_parameters.
220   ASSIGN_OR_RETURN(
221       std::unique_ptr<BbObliviousSignature> bb_oblivious_signature,
222       CreateBbObliviousSignature(scheme_parameters_v0,
223                                  *server_public_parameters_v0, &ctx, &ec_group,
224                                  pedersen.get(), public_camenisch_shoup.get()));
225 
226   // Generate Boneh-Boyen Oblivious Signature key.
227   ASSIGN_OR_RETURN(
228       std::tie(*server_public_parameters_v0
229                     ->mutable_bb_oblivious_signature_public_key(),
230                *server_private_parameters_v0
231                     ->mutable_bb_oblivious_signature_private_key()),
232       bb_oblivious_signature->GenerateKeys());
233 
234   return std::move(server_parameters);
235 }
236 
237 // Returns a fresh set of Client parameters corresponding to these
238 // SchemeParameters and ServerPublicParameters. Fails with InvalidArgument if
239 // the parameters don't correspond to ACT v0.
GenerateClientParameters(const SchemeParameters & scheme_parameters,const ServerPublicParameters & server_public_parameters)240 StatusOr<ClientParameters> AnonymousCountingTokensV0::GenerateClientParameters(
241     const SchemeParameters& scheme_parameters,
242     const ServerPublicParameters& server_public_parameters) {
243   if (!scheme_parameters.has_scheme_parameters_v0() ||
244       !server_public_parameters.has_server_public_parameters_v0()) {
245     return absl::InvalidArgumentError(
246         "AnonymousCountingTokensV0::GenerateClientParameters: supplied "
247         "parameters do not correspond to ACT v0.");
248   }
249 
250   const SchemeParametersV0& scheme_parameters_v0 =
251       scheme_parameters.scheme_parameters_v0();
252   const ServerPublicParametersV0& server_public_parameters_v0 =
253       server_public_parameters.server_public_parameters_v0();
254 
255   Context ctx;
256   ASSIGN_OR_RETURN(ECGroup ec_group,
257                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
258 
259   // Deserialize Pedersen Params
260   ASSIGN_OR_RETURN(
261       std::unique_ptr<PedersenOverZn> pedersen,
262       PedersenOverZn::FromProto(
263           &ctx, server_public_parameters_v0.pedersen_parameters()));
264 
265   // Generate Client VRF object.
266   ASSIGN_OR_RETURN(
267       std::unique_ptr<DyVerifiableRandomFunction> dy_vrf,
268       CreateDyVrf(scheme_parameters_v0, server_public_parameters_v0, &ctx,
269                   &ec_group, pedersen.get()));
270 
271   ClientParameters client_parameters;
272   ClientPublicParametersV0* client_public_parameters_v0 =
273       client_parameters.mutable_public_parameters()
274           ->mutable_client_public_parameters_v0();
275   ClientPrivateParametersV0* client_private_parameters_v0 =
276       client_parameters.mutable_private_parameters()
277           ->mutable_client_private_parameters_v0();
278 
279   ASSIGN_OR_RETURN(
280       std::tie(
281           *client_public_parameters_v0->mutable_dy_vrf_public_key(),
282           *client_private_parameters_v0->mutable_dy_vrf_private_key(),
283           *client_public_parameters_v0->mutable_dy_vrf_generate_keys_proof()),
284       dy_vrf->GenerateKeyPair());
285 
286   return std::move(client_parameters);
287 }
288 
289 // Verifies the consistency of the  ClientPublicParameters with the Server and
290 // scheme parameters. Fails with InvalidArgument if the parameters don't
291 // correspond to ACT v0.
CheckClientParameters(const SchemeParameters & scheme_parameters,const ClientPublicParameters & client_public_parameters,const ServerPublicParameters & server_public_parameters,const ServerPrivateParameters & server_private_parameters)292 Status AnonymousCountingTokensV0::CheckClientParameters(
293     const SchemeParameters& scheme_parameters,
294     const ClientPublicParameters& client_public_parameters,
295     const ServerPublicParameters& server_public_parameters,
296     const ServerPrivateParameters& server_private_parameters) {
297   if (!scheme_parameters.has_scheme_parameters_v0() ||
298       !client_public_parameters.has_client_public_parameters_v0() ||
299       !server_public_parameters.has_server_public_parameters_v0() ||
300       !server_private_parameters.has_server_private_parameters_v0()) {
301     return absl::InvalidArgumentError(
302         "AnonymousCountingTokensV0::CheckClientParameters: supplied "
303         "parameters do not correspond to ACT v0.");
304   }
305 
306   const SchemeParametersV0& scheme_parameters_v0 =
307       scheme_parameters.scheme_parameters_v0();
308   const ServerPublicParametersV0& server_public_parameters_v0 =
309       server_public_parameters.server_public_parameters_v0();
310   const ClientPublicParametersV0& client_public_parameters_v0 =
311       client_public_parameters.client_public_parameters_v0();
312   Context ctx;
313   ASSIGN_OR_RETURN(ECGroup ec_group,
314                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
315 
316   // Deserialize Pedersen Params
317   ASSIGN_OR_RETURN(
318       std::unique_ptr<PedersenOverZn> pedersen,
319       PedersenOverZn::FromProto(
320           &ctx, server_public_parameters_v0.pedersen_parameters()));
321 
322   // Generate Client VRF object.
323   ASSIGN_OR_RETURN(
324       std::unique_ptr<DyVerifiableRandomFunction> dy_vrf,
325       CreateDyVrf(scheme_parameters_v0, server_public_parameters_v0, &ctx,
326                   &ec_group, pedersen.get()));
327 
328   // Verify the proof for the Client's VRF key.
329   return dy_vrf->VerifyGenerateKeysProof(
330       client_public_parameters_v0.dy_vrf_public_key(),
331       client_public_parameters_v0.dy_vrf_generate_keys_proof());
332 }
333 
334 // Returns a tuple of client_fingerprints, TokensRequest and
335 // TokensRequestPrivateState for the given set of messages. Fails with
336 // InvalidArgument if the parameters don't correspond to ACT v0.
337 StatusOr<std::tuple<std::vector<std::string>, TokensRequest,
338                     TokensRequestPrivateState>>
GenerateTokensRequest(absl::Span<const std::string> messages,const SchemeParameters & scheme_parameters,const ClientPublicParameters & client_public_parameters,const ClientPrivateParameters & client_private_parameters,const ServerPublicParameters & server_public_parameters)339 AnonymousCountingTokensV0::GenerateTokensRequest(
340     absl::Span<const std::string> messages,
341     const SchemeParameters& scheme_parameters,
342     const ClientPublicParameters& client_public_parameters,
343     const ClientPrivateParameters& client_private_parameters,
344     const ServerPublicParameters& server_public_parameters) {
345   if (!scheme_parameters.has_scheme_parameters_v0() ||
346       !client_public_parameters.has_client_public_parameters_v0() ||
347       !client_private_parameters.has_client_private_parameters_v0() ||
348       !server_public_parameters.has_server_public_parameters_v0()) {
349     return absl::InvalidArgumentError(
350         "AnonymousCountingTokensV0::GenerateTokensRequest: supplied "
351         "parameters do not correspond to ACT v0.");
352   }
353 
354   const SchemeParametersV0& scheme_parameters_v0 =
355       scheme_parameters.scheme_parameters_v0();
356   const ClientPublicParametersV0& client_public_parameters_v0 =
357       client_public_parameters.client_public_parameters_v0();
358   const ClientPrivateParametersV0& client_private_parameters_v0 =
359       client_private_parameters.client_private_parameters_v0();
360   const ServerPublicParametersV0& server_public_parameters_v0 =
361       server_public_parameters.server_public_parameters_v0();
362 
363   TokensRequest tokens_request_proto;
364   TokensRequestV0* tokens_request_v0 =
365       tokens_request_proto.mutable_tokens_request_v0();
366   TokensRequestV0::Part1* tokens_request_v0_part_1 =
367       tokens_request_v0->mutable_part_1();
368   TokensRequestPrivateState tokens_request_private_state;
369 
370   Context ctx;
371   ASSIGN_OR_RETURN(ECGroup ec_group,
372                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
373 
374   // Deserialize and create cryptographic objects.
375   ASSIGN_OR_RETURN(
376       std::unique_ptr<PedersenOverZn> pedersen,
377       PedersenOverZn::FromProto(
378           &ctx, server_public_parameters_v0.pedersen_parameters()));
379   ASSIGN_OR_RETURN(
380       std::unique_ptr<PublicCamenischShoup> public_camenisch_shoup,
381       PublicCamenischShoup::FromProto(
382           &ctx, server_public_parameters_v0.camenisch_shoup_public_key()));
383   ASSIGN_OR_RETURN(
384       ECPoint dy_prf_base_g,
385       ec_group.CreateECPoint(server_public_parameters_v0.prf_base_g()));
386 
387   ASSIGN_OR_RETURN(
388       std::unique_ptr<DyVerifiableRandomFunction> dy_vrf,
389       CreateDyVrf(scheme_parameters_v0, server_public_parameters_v0, &ctx,
390                   &ec_group, pedersen.get()));
391 
392   // Deserialize Boneh-Boyen Oblivious Signature parameters and keys
393   ASSIGN_OR_RETURN(
394       std::unique_ptr<BbObliviousSignature> bb_oblivious_signature,
395       CreateBbObliviousSignature(scheme_parameters_v0,
396                                  server_public_parameters_v0, &ctx, &ec_group,
397                                  pedersen.get(), public_camenisch_shoup.get()));
398 
399   // 1) Hash all messages to the exponent group/ BigNums.
400   std::vector<BigNum> hashed_messages;
401   hashed_messages.reserve(messages.size());
402   for (size_t i = 0; i < messages.size(); ++i) {
403     hashed_messages.push_back(
404         ctx.RandomOracleSha512(messages[i], ec_group.GetOrder()));
405   }
406 
407   // 2) Commit to hashed messages.
408   ASSIGN_OR_RETURN(
409       PedersenOverZn::CommitmentAndOpening commit_and_open_messages,
410       pedersen->Commit(hashed_messages));
411   tokens_request_v0_part_1->set_commit_messages(
412       commit_and_open_messages.commitment.ToBytes());
413 
414   // 3) Generate client nonces and commit to them.
415   std::vector<BigNum> client_nonces;
416   client_nonces.reserve(messages.size());
417   for (size_t i = 0; i < messages.size(); ++i) {
418     client_nonces.push_back(ec_group.GeneratePrivateKey());
419   }
420   ASSIGN_OR_RETURN(
421       PedersenOverZn::CommitmentAndOpening commit_and_open_client_nonces,
422       pedersen->Commit(client_nonces));
423   tokens_request_v0_part_1->set_commit_client_nonces(
424       commit_and_open_client_nonces.commitment.ToBytes());
425 
426   // 4) Perform a VRF on the committed messages and serialize as fingerprints.
427   ASSIGN_OR_RETURN(
428       std::vector<ECPoint> prf_evaluations,
429       dy_vrf->Apply(hashed_messages,
430                     client_private_parameters_v0.dy_vrf_private_key()));
431   std::vector<std::string> fingerprints;
432   fingerprints.reserve(prf_evaluations.size());
433   for (size_t i = 0; i < prf_evaluations.size(); ++i) {
434     ASSIGN_OR_RETURN(std::string fingerprint,
435                      prf_evaluations[i].ToBytesCompressed());
436     fingerprints.push_back(std::move(fingerprint));
437   }
438 
439   // Also create the proof that the fingerprints were correctly generated.
440   ASSIGN_OR_RETURN(*tokens_request_v0_part_1->mutable_fingerprints_proof(),
441                    dy_vrf->GenerateApplyProof(
442                        hashed_messages, prf_evaluations,
443                        client_public_parameters_v0.dy_vrf_public_key(),
444                        client_private_parameters_v0.dy_vrf_private_key(),
445                        commit_and_open_messages));
446 
447   // 5) Generate server nonces by hashing the preceding portion of the request.
448   ASSIGN_OR_RETURN(std::vector<BigNum> server_nonces,
449                    GetNoncesForTokenRequest(
450                        &ctx, scheme_parameters, server_public_parameters,
451                        client_public_parameters, *tokens_request_v0_part_1,
452                        messages.size()));
453   // We commit the "server_nonces" with randomness 0, which is ok since they
454   // are known to both parties, and furthermore will be homomorphically added to
455   // the "client_nonces" which have properly generated randomness.
456   ASSIGN_OR_RETURN(PedersenOverZn::Commitment commit_server_nonces,
457                    pedersen->CommitWithRand(server_nonces, ctx.Zero()));
458 
459   // 6) Homomorphically compute commitments to the nonces (rs)
460   std::vector<BigNum> nonces;
461   nonces.reserve(messages.size());
462   for (size_t i = 0; i < messages.size(); ++i) {
463     // No mod performed here, since the homomorphic addition of the commitments
464     // will not be mod-ed, and we want consistency.
465     nonces.push_back(server_nonces[i] + client_nonces[i]);
466   }
467   PedersenOverZn::Commitment commit_nonce = pedersen->Add(
468       commit_server_nonces, commit_and_open_client_nonces.commitment);
469   PedersenOverZn::Opening commit_nonce_opening =
470       commit_and_open_client_nonces.opening;
471 
472   *tokens_request_private_state.mutable_tokens_request_private_state_v0()
473        ->mutable_nonces() = BigNumVectorToProto(nonces);
474 
475   // 7) Generate Boneh-Boyen Oblivious Signature Request request.
476   ASSIGN_OR_RETURN(
477       std::tie(
478           *tokens_request_v0->mutable_bb_oblivious_signature_request(),
479           *tokens_request_v0->mutable_bb_oblivious_signature_request_proof(),
480           *tokens_request_private_state
481                .mutable_tokens_request_private_state_v0()
482                ->mutable_bb_oblivious_signature_request_private_state()),
483       bb_oblivious_signature->GenerateRequestAndProof(
484           hashed_messages, nonces,
485           server_public_parameters_v0.bb_oblivious_signature_public_key(),
486           commit_and_open_messages, {commit_nonce, commit_nonce_opening}));
487 
488   return std::make_tuple(std::move(fingerprints),
489                          std::move(tokens_request_proto),
490                          std::move(tokens_request_private_state));
491 }
492 
493 // Returns OkStatus on a valid request. Fails with InvalidArgument if the
494 // parameters don't correspond to ACT v0.
CheckTokensRequest(absl::Span<const std::string> client_fingerprints,const TokensRequest & tokens_request,const SchemeParameters & scheme_parameters,const ClientPublicParameters & client_public_parameters,const ServerPublicParameters & server_public_parameters,const ServerPrivateParameters & server_private_parameters)495 Status AnonymousCountingTokensV0::CheckTokensRequest(
496     absl::Span<const std::string> client_fingerprints,
497     const TokensRequest& tokens_request,
498     const SchemeParameters& scheme_parameters,
499     const ClientPublicParameters& client_public_parameters,
500     const ServerPublicParameters& server_public_parameters,
501     const ServerPrivateParameters& server_private_parameters) {
502   if (!tokens_request.has_tokens_request_v0() ||
503       !scheme_parameters.has_scheme_parameters_v0() ||
504       !client_public_parameters.has_client_public_parameters_v0() ||
505       !server_public_parameters.has_server_public_parameters_v0()) {
506     return absl::InvalidArgumentError(
507         "AnonymousCountingTokensV0::GenerateTokensResponse: supplied "
508         "parameters do not correspond to ACT v0.");
509   }
510 
511   const TokensRequestV0& tokens_request_v0 = tokens_request.tokens_request_v0();
512   const SchemeParametersV0& scheme_parameters_v0 =
513       scheme_parameters.scheme_parameters_v0();
514   const ClientPublicParametersV0& client_public_parameters_v0 =
515       client_public_parameters.client_public_parameters_v0();
516   const ServerPublicParametersV0& server_public_parameters_v0 =
517       server_public_parameters.server_public_parameters_v0();
518 
519   Context ctx;
520   ASSIGN_OR_RETURN(ECGroup ec_group,
521                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
522 
523   // Deserialize and create cryptographic objects.
524   ASSIGN_OR_RETURN(
525       std::unique_ptr<PedersenOverZn> pedersen,
526       PedersenOverZn::FromProto(
527           &ctx, server_public_parameters_v0.pedersen_parameters()));
528   ASSIGN_OR_RETURN(
529       std::unique_ptr<PublicCamenischShoup> public_camenisch_shoup,
530       PublicCamenischShoup::FromProto(
531           &ctx, server_public_parameters_v0.camenisch_shoup_public_key()));
532 
533   // Construct the DY VRF object
534   ASSIGN_OR_RETURN(
535       std::unique_ptr<DyVerifiableRandomFunction> dy_vrf,
536       CreateDyVrf(scheme_parameters_v0, server_public_parameters_v0, &ctx,
537                   &ec_group, pedersen.get()));
538 
539   PedersenOverZn::Commitment commit_messages = ctx.CreateBigNum(
540       tokens_request.tokens_request_v0().part_1().commit_messages());
541 
542   std::vector<ECPoint> deserialized_fingerprints;
543   deserialized_fingerprints.reserve(client_fingerprints.size());
544   for (size_t i = 0; i < client_fingerprints.size(); ++i) {
545     ASSIGN_OR_RETURN(ECPoint deserialized_fingerprint,
546                      ec_group.CreateECPoint(client_fingerprints[i]));
547 
548     // Test that the deserialized fingerprint reserializes to the exact same
549     // value.
550     ASSIGN_OR_RETURN(std::string reserialized_fingerprint,
551                      deserialized_fingerprint.ToBytesCompressed());
552     if (reserialized_fingerprint != client_fingerprints[i]) {
553       return absl::InvalidArgumentError(absl::StrCat(
554           "AnonymousCountingTokensV0::CheckTokensRequest: client_fingerprints[",
555           i,
556           "] comes out to a different value when serialized and "
557           "deserialized."));
558     }
559 
560     deserialized_fingerprints.push_back(std::move(deserialized_fingerprint));
561   }
562 
563   RETURN_IF_ERROR(dy_vrf->VerifyApplyProof(
564       deserialized_fingerprints,
565       client_public_parameters_v0.dy_vrf_public_key(), commit_messages,
566       tokens_request_v0.part_1().fingerprints_proof()));
567 
568   // Deserialize Boneh-Boyen Oblivious Signature parameters and keys
569   ASSIGN_OR_RETURN(
570       std::unique_ptr<BbObliviousSignature> bb_oblivious_signature,
571       CreateBbObliviousSignature(scheme_parameters_v0,
572                                  server_public_parameters_v0, &ctx, &ec_group,
573                                  pedersen.get(), public_camenisch_shoup.get()));
574 
575   // Regenerate the commitments to messages and nonces (rs) by replaying the
576   // steps the client took to generate them.
577   PedersenOverZn::Commitment commit_client_nonces = ctx.CreateBigNum(
578       tokens_request.tokens_request_v0().part_1().commit_client_nonces());
579 
580   ASSIGN_OR_RETURN(
581       std::vector<BigNum> server_nonces,
582       GetNoncesForTokenRequest(
583           &ctx, scheme_parameters, server_public_parameters,
584           client_public_parameters, tokens_request.tokens_request_v0().part_1(),
585           tokens_request.tokens_request_v0()
586               .bb_oblivious_signature_request()
587               .num_messages()));
588   ASSIGN_OR_RETURN(PedersenOverZn::Commitment commit_server_nonces,
589                    pedersen->CommitWithRand(server_nonces, ctx.Zero()));
590   PedersenOverZn::Commitment commit_nonce =
591       pedersen->Add(commit_server_nonces, commit_client_nonces);
592 
593   return bb_oblivious_signature->VerifyRequest(
594       server_public_parameters_v0.bb_oblivious_signature_public_key(),
595       tokens_request_v0.bb_oblivious_signature_request(),
596       tokens_request_v0.bb_oblivious_signature_request_proof(), commit_messages,
597       commit_nonce);
598 }
599 
600 // Returns the TokensResponse. Fails with InvalidArgument if the parameters
601 // don't correspond to ACT v0.
GenerateTokensResponse(const TokensRequest & tokens_request,const SchemeParameters & scheme_parameters,const ClientPublicParameters & client_public_parameters,const ServerPublicParameters & server_public_parameters,const ServerPrivateParameters & server_private_parameters)602 StatusOr<TokensResponse> AnonymousCountingTokensV0::GenerateTokensResponse(
603     const TokensRequest& tokens_request,
604     const SchemeParameters& scheme_parameters,
605     const ClientPublicParameters& client_public_parameters,
606     const ServerPublicParameters& server_public_parameters,
607     const ServerPrivateParameters& server_private_parameters) {
608   if (!tokens_request.has_tokens_request_v0() ||
609       !scheme_parameters.has_scheme_parameters_v0() ||
610       !client_public_parameters.has_client_public_parameters_v0() ||
611       !server_public_parameters.has_server_public_parameters_v0() ||
612       !server_private_parameters.has_server_private_parameters_v0()) {
613     return absl::InvalidArgumentError(
614         "AnonymousCountingTokensV0::GenerateTokensResponse: supplied "
615         "parameters do not correspond to ACT v0.");
616   }
617 
618   const TokensRequestV0& tokens_request_v0 = tokens_request.tokens_request_v0();
619   const SchemeParametersV0& scheme_parameters_v0 =
620       scheme_parameters.scheme_parameters_v0();
621   const ServerPublicParametersV0& server_public_parameters_v0 =
622       server_public_parameters.server_public_parameters_v0();
623   const ServerPrivateParametersV0& server_private_parameters_v0 =
624       server_private_parameters.server_private_parameters_v0();
625 
626   TokensResponse tokens_response;
627   TokensResponseV0* tokens_response_v0 =
628       tokens_response.mutable_tokens_response_v0();
629 
630   Context ctx;
631   ASSIGN_OR_RETURN(ECGroup ec_group,
632                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
633 
634   // Deserialize and create cryptographic objects.
635   ASSIGN_OR_RETURN(
636       std::unique_ptr<PedersenOverZn> pedersen,
637       PedersenOverZn::FromProto(
638           &ctx, server_public_parameters_v0.pedersen_parameters()));
639   ASSIGN_OR_RETURN(
640       std::unique_ptr<PublicCamenischShoup> public_camenisch_shoup,
641       PublicCamenischShoup::FromProto(
642           &ctx, server_public_parameters_v0.camenisch_shoup_public_key()));
643   ASSIGN_OR_RETURN(
644       std::unique_ptr<PrivateCamenischShoup> private_camenisch_shoup,
645       PrivateCamenischShoup::FromProto(
646           &ctx, server_public_parameters_v0.camenisch_shoup_public_key(),
647           server_private_parameters_v0.camenisch_shoup_private_key()));
648 
649   // Deserialize Boneh-Boyen Oblivious Signature parameters and keys
650   ASSIGN_OR_RETURN(
651       std::unique_ptr<BbObliviousSignature> bb_oblivious_signature,
652       CreateBbObliviousSignature(scheme_parameters_v0,
653                                  server_public_parameters_v0, &ctx, &ec_group,
654                                  pedersen.get(), public_camenisch_shoup.get()));
655 
656   // Regenerate the commitments to messages and nonces (rs) by replaying the
657   // steps the client took to generate them.
658   PedersenOverZn::Commitment commit_messages = ctx.CreateBigNum(
659       tokens_request.tokens_request_v0().part_1().commit_messages());
660   PedersenOverZn::Commitment commit_client_nonces = ctx.CreateBigNum(
661       tokens_request.tokens_request_v0().part_1().commit_client_nonces());
662 
663   ASSIGN_OR_RETURN(
664       std::vector<BigNum> server_nonces,
665       GetNoncesForTokenRequest(
666           &ctx, scheme_parameters, server_public_parameters,
667           client_public_parameters, tokens_request.tokens_request_v0().part_1(),
668           tokens_request.tokens_request_v0()
669               .bb_oblivious_signature_request()
670               .num_messages()));
671   ASSIGN_OR_RETURN(PedersenOverZn::Commitment commit_server_nonces,
672                    pedersen->CommitWithRand(server_nonces, ctx.Zero()));
673   PedersenOverZn::Commitment commit_nonce =
674       pedersen->Add(commit_server_nonces, commit_client_nonces);
675 
676   // Generate response and proof for the Boneh-Boyen Oblivious Signature.
677   ASSIGN_OR_RETURN(
678       std::tie(
679           *tokens_response_v0->mutable_bb_oblivious_signature_response(),
680           *tokens_response_v0->mutable_bb_oblivious_signature_response_proof()),
681       bb_oblivious_signature->GenerateResponseAndProof(
682           tokens_request_v0.bb_oblivious_signature_request(),
683           server_public_parameters_v0.bb_oblivious_signature_public_key(),
684           server_private_parameters_v0.bb_oblivious_signature_private_key(),
685           commit_messages, commit_nonce, private_camenisch_shoup.get()));
686 
687   return std::move(tokens_response);
688 }
689 
690 // Returns OkStatus on a valid response. Fails with InvalidArgument if the
691 // parameters don't correspond to ACT v0.
VerifyTokensResponse(absl::Span<const std::string> messages,const TokensRequest & tokens_request,const TokensRequestPrivateState & tokens_request_private_state,const TokensResponse & tokens_response,const SchemeParameters & scheme_parameters,const ClientPublicParameters & client_public_parameters,const ClientPrivateParameters & client_private_parameters,const ServerPublicParameters & server_public_parameters)692 Status AnonymousCountingTokensV0::VerifyTokensResponse(
693     absl::Span<const std::string> messages, const TokensRequest& tokens_request,
694     const TokensRequestPrivateState& tokens_request_private_state,
695     const TokensResponse& tokens_response,
696     const SchemeParameters& scheme_parameters,
697     const ClientPublicParameters& client_public_parameters,
698     const ClientPrivateParameters& client_private_parameters,
699     const ServerPublicParameters& server_public_parameters) {
700   if (!tokens_request.has_tokens_request_v0() ||
701       !tokens_response.has_tokens_response_v0() ||
702       !tokens_request_private_state.has_tokens_request_private_state_v0() ||
703       !scheme_parameters.has_scheme_parameters_v0() ||
704       !client_public_parameters.has_client_public_parameters_v0() ||
705       !client_private_parameters.has_client_private_parameters_v0() ||
706       !server_public_parameters.has_server_public_parameters_v0()) {
707     return absl::InvalidArgumentError(
708         "AnonymousCountingTokensV0::VerifyTokensResponse: supplied "
709         "parameters do not correspond to ACT v0.");
710   }
711 
712   const TokensRequestV0& tokens_request_v0 = tokens_request.tokens_request_v0();
713   const SchemeParametersV0& scheme_parameters_v0 =
714       scheme_parameters.scheme_parameters_v0();
715   const ServerPublicParametersV0& server_public_parameters_v0 =
716       server_public_parameters.server_public_parameters_v0();
717   const TokensResponseV0& tokens_response_v0 =
718       tokens_response.tokens_response_v0();
719 
720   Context ctx;
721   ASSIGN_OR_RETURN(ECGroup ec_group,
722                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
723 
724   // Deserialize and create cryptographic objects.
725   ASSIGN_OR_RETURN(
726       std::unique_ptr<PedersenOverZn> pedersen,
727       PedersenOverZn::FromProto(
728           &ctx, server_public_parameters_v0.pedersen_parameters()));
729   ASSIGN_OR_RETURN(
730       std::unique_ptr<PublicCamenischShoup> public_camenisch_shoup,
731       PublicCamenischShoup::FromProto(
732           &ctx, server_public_parameters_v0.camenisch_shoup_public_key()));
733 
734   // Deserialize Boneh-Boyen Oblivious Signature parameters and keys
735   ASSIGN_OR_RETURN(
736       std::unique_ptr<BbObliviousSignature> bb_oblivious_signature,
737       CreateBbObliviousSignature(scheme_parameters_v0,
738                                  server_public_parameters_v0, &ctx, &ec_group,
739                                  pedersen.get(), public_camenisch_shoup.get()));
740 
741   // Regenerate the commitments to messages and nonces (rs) by replaying the
742   // steps the client took to generate them.
743   PedersenOverZn::Commitment commit_messages = ctx.CreateBigNum(
744       tokens_request.tokens_request_v0().part_1().commit_messages());
745   PedersenOverZn::Commitment commit_client_nonces = ctx.CreateBigNum(
746       tokens_request.tokens_request_v0().part_1().commit_client_nonces());
747 
748   ASSIGN_OR_RETURN(
749       std::vector<BigNum> server_nonces,
750       GetNoncesForTokenRequest(
751           &ctx, scheme_parameters, server_public_parameters,
752           client_public_parameters, tokens_request.tokens_request_v0().part_1(),
753           tokens_request.tokens_request_v0()
754               .bb_oblivious_signature_request()
755               .num_messages()));
756   ASSIGN_OR_RETURN(PedersenOverZn::Commitment commit_server_nonces,
757                    pedersen->CommitWithRand(server_nonces, ctx.Zero()));
758   PedersenOverZn::Commitment commit_nonce =
759       pedersen->Add(commit_server_nonces, commit_client_nonces);
760 
761   return bb_oblivious_signature->VerifyResponse(
762       server_public_parameters_v0.bb_oblivious_signature_public_key(),
763       tokens_response_v0.bb_oblivious_signature_response(),
764       tokens_response_v0.bb_oblivious_signature_response_proof(),
765       tokens_request_v0.bb_oblivious_signature_request(), commit_messages,
766       commit_nonce);
767 }
768 
769 // Returns a vector of tokens corresponding to the supplied messages. Fails
770 // with InvalidArgument if the parameters don't correspond to ACT v0.
RecoverTokens(absl::Span<const std::string> messages,const TokensRequest & tokens_request,const TokensRequestPrivateState & tokens_request_private_state,const TokensResponse & tokens_response,const SchemeParameters & scheme_parameters,const ClientPublicParameters & client_public_parameters,const ClientPrivateParameters & client_private_parameters,const ServerPublicParameters & server_public_parameters)771 StatusOr<std::vector<Token>> AnonymousCountingTokensV0::RecoverTokens(
772     absl::Span<const std::string> messages, const TokensRequest& tokens_request,
773     const TokensRequestPrivateState& tokens_request_private_state,
774     const TokensResponse& tokens_response,
775     const SchemeParameters& scheme_parameters,
776     const ClientPublicParameters& client_public_parameters,
777     const ClientPrivateParameters& client_private_parameters,
778     const ServerPublicParameters& server_public_parameters) {
779   if (!tokens_request.has_tokens_request_v0() ||
780       !tokens_request_private_state.has_tokens_request_private_state_v0() ||
781       !tokens_response.has_tokens_response_v0() ||
782       !scheme_parameters.has_scheme_parameters_v0() ||
783       !client_public_parameters.has_client_public_parameters_v0() ||
784       !client_private_parameters.has_client_private_parameters_v0() ||
785       !server_public_parameters.has_server_public_parameters_v0()) {
786     return absl::InvalidArgumentError(
787         "AnonymousCountingTokensV0::VerifyTokensResponse: supplied "
788         "parameters do not correspond to ACT v0.");
789   }
790 
791   const TokensRequestV0& tokens_request_v0 = tokens_request.tokens_request_v0();
792   const TokensRequestPrivateStateV0& tokens_request_private_state_v0 =
793       tokens_request_private_state.tokens_request_private_state_v0();
794   const TokensResponseV0& tokens_response_v0 =
795       tokens_response.tokens_response_v0();
796   const SchemeParametersV0& scheme_parameters_v0 =
797       scheme_parameters.scheme_parameters_v0();
798   const ServerPublicParametersV0& server_public_parameters_v0 =
799       server_public_parameters.server_public_parameters_v0();
800 
801   Context ctx;
802   ASSIGN_OR_RETURN(ECGroup ec_group,
803                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
804 
805   // Deserialize and create cryptographic objects.
806   ASSIGN_OR_RETURN(
807       std::unique_ptr<PedersenOverZn> pedersen,
808       PedersenOverZn::FromProto(
809           &ctx, server_public_parameters_v0.pedersen_parameters()));
810   ASSIGN_OR_RETURN(
811       std::unique_ptr<PublicCamenischShoup> public_camenisch_shoup,
812       PublicCamenischShoup::FromProto(
813           &ctx, server_public_parameters_v0.camenisch_shoup_public_key()));
814   ASSIGN_OR_RETURN(
815       ECPoint dy_prf_base_g,
816       ec_group.CreateECPoint(server_public_parameters_v0.prf_base_g()));
817 
818   // Deserialize Boneh-Boyen Oblivious Signature parameters and keys
819   ASSIGN_OR_RETURN(
820       std::unique_ptr<BbObliviousSignature> bb_oblivious_signature,
821       CreateBbObliviousSignature(scheme_parameters_v0,
822                                  server_public_parameters_v0, &ctx, &ec_group,
823                                  pedersen.get(), public_camenisch_shoup.get()));
824 
825   // Extract message PRF evaluations
826   ASSIGN_OR_RETURN(std::vector<ECPoint> signatures,
827                    bb_oblivious_signature->ExtractResults(
828                        tokens_response_v0.bb_oblivious_signature_response(),
829                        tokens_request_v0.bb_oblivious_signature_request(),
830                        tokens_request_private_state_v0
831                            .bb_oblivious_signature_request_private_state()));
832 
833   // Package tokens.
834   std::vector<BigNum> nonces =
835       ParseBigNumVectorProto(&ctx, tokens_request_private_state_v0.nonces());
836 
837   std::vector<Token> tokens;
838   tokens.reserve(messages.size());
839   for (size_t i = 0; i < messages.size(); ++i) {
840     Token token;
841     TokenV0* token_v0 = token.mutable_token_v0();
842     token.set_nonce_bytes(nonces[i].ToBytes());
843     ASSIGN_OR_RETURN(*token_v0->mutable_bb_signature(),
844                      signatures[i].ToBytesCompressed());
845     tokens.push_back(std::move(token));
846   }
847 
848   return std::move(tokens);
849 }
850 
851 // Returns OkStatus on valid tokens. Fails with InvalidArgument if the
852 // parameters don't correspond to ACT v0.
VerifyToken(std::string m,const Token & token,const SchemeParameters & scheme_parameters,const ServerPublicParameters & server_public_parameters,const ServerPrivateParameters & server_private_parameters)853 Status AnonymousCountingTokensV0::VerifyToken(
854     std::string m, const Token& token,
855     const SchemeParameters& scheme_parameters,
856     const ServerPublicParameters& server_public_parameters,
857     const ServerPrivateParameters& server_private_parameters) {
858   if (!token.has_token_v0() || !scheme_parameters.has_scheme_parameters_v0() ||
859       !server_public_parameters.has_server_public_parameters_v0() ||
860       !server_private_parameters.has_server_private_parameters_v0()) {
861     return absl::InvalidArgumentError(
862         "AnonymousCountingTokensV0::VerifyToken: supplied "
863         "parameters do not correspond to ACT v0.");
864   }
865 
866   const TokenV0& token_v0 = token.token_v0();
867   const SchemeParametersV0& scheme_parameters_v0 =
868       scheme_parameters.scheme_parameters_v0();
869   const ServerPublicParametersV0& server_public_parameters_v0 =
870       server_public_parameters.server_public_parameters_v0();
871   const ServerPrivateParametersV0& server_private_parameters_v0 =
872       server_private_parameters.server_private_parameters_v0();
873 
874   Context ctx;
875   ASSIGN_OR_RETURN(ECGroup ec_group,
876                    ECGroup::Create(scheme_parameters_v0.prf_ec_group(), &ctx));
877   ASSIGN_OR_RETURN(
878       ECPoint dy_prf_base_g,
879       ec_group.CreateECPoint(server_public_parameters_v0.prf_base_g()));
880   BigNum k = ctx.CreateBigNum(
881       server_private_parameters_v0.bb_oblivious_signature_private_key().k());
882   BigNum y = ctx.CreateBigNum(
883       server_private_parameters_v0.bb_oblivious_signature_private_key().y());
884 
885   BigNum hashed_message = ctx.RandomOracleSha512(m, ec_group.GetOrder());
886 
887   BigNum nonce = ctx.CreateBigNum(token.nonce_bytes());
888 
889   // Verify that reserializing the nonce comes out to the same value.
890   if (nonce.ToBytes() != token.nonce_bytes()) {
891     return absl::InvalidArgumentError(
892         "AnonymousCountingTokensV0::VerifyToken: nonce comes out to different "
893         "value when serialized and deserialized.");
894   }
895 
896   ASSIGN_OR_RETURN(ECPoint signature_from_token,
897                    ec_group.CreateECPoint(token_v0.bb_signature()));
898 
899   // Verify that reserializing the signature comes out to the same value
900   ASSIGN_OR_RETURN(std::string reserialized_signature_from_token,
901                    signature_from_token.ToBytesCompressed());
902   if (reserialized_signature_from_token != token_v0.bb_signature()) {
903     return absl::InvalidArgumentError(
904         "AnonymousCountingTokensV0::VerifyToken: bb_signature comes out to "
905         "different value when serialized and deserialized.");
906   }
907 
908   ASSIGN_OR_RETURN(
909       BigNum inverted_exponent,
910       (hashed_message + k + (nonce * y)).ModInverse(ec_group.GetOrder()));
911   ASSIGN_OR_RETURN(ECPoint signature_by_evaluation,
912                    dy_prf_base_g.Mul(inverted_exponent));
913   if (signature_by_evaluation != signature_from_token) {
914     return absl::InvalidArgumentError(
915         "ACTV0::VerifyToken: Boneh-boyen signature on message and nonce fails "
916         "to match the token.");
917   }
918 
919   return absl::OkStatus();
920 }
921 
922 }  // namespace anonymous_counting_tokens
923 }  // namespace private_join_and_compute
924