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