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