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