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