Updating anonymous token signing client-side code to start using public metadata in calls to cryptographic libraries.

PiperOrigin-RevId: 525817000
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.cc
index 2ccd9c5..77e2e9e 100644
--- a/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.cc
+++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.cc
@@ -120,20 +120,20 @@
 
   AnonymousTokensSignRequest request;
   for (const PlaintextMessageWithPublicMetadata& input : inputs) {
-    if (input.plaintext_message().empty()) {
-      return absl::InvalidArgumentError(
-          "Cannot send an empty message to sign.");
-    }
-
     // Generate nonce and masked message. For more details, see
     // https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/
     ANON_TOKENS_ASSIGN_OR_RETURN(std::string mask, GenerateMask(public_key_));
     std::string masked_message =
         MaskMessageConcat(mask, input.plaintext_message());
 
+    std::optional<std::string> public_metadata = std::nullopt;
+    if (public_key_.public_metadata_support()) {
+      // Empty public metadata is a valid value.
+      public_metadata = input.public_metadata();
+    }
     // Generate RSA blinder.
     ANON_TOKENS_ASSIGN_OR_RETURN(auto rsa_bssa_blinder,
-                                 RsaBlinder::New(public_key_));
+                                 RsaBlinder::New(public_key_, public_metadata));
     ANON_TOKENS_ASSIGN_OR_RETURN(const std::string blinded_message,
                                  rsa_bssa_blinder->Blind(masked_message));
 
@@ -217,7 +217,7 @@
     if (blinding_info.input.public_metadata() !=
         anonymous_token.public_metadata()) {
       return absl::InvalidArgumentError(
-          "Response metadata does not match input.");
+          "Response public metadata does not match input.");
     }
 
     // Unblind the blinded anonymous token to obtain the final anonymous token
@@ -246,8 +246,9 @@
 }
 
 absl::Status AnonymousTokensRsaBssaClient::Verify(
-    const RSABlindSignatureToken& /*token*/, absl::string_view /*message*/,
-    absl::optional<absl::string_view> /*public_metadata*/) {
+    const RSABlindSignaturePublicKey& /*public_key*/,
+    const RSABlindSignatureToken& /*token*/,
+    const PlaintextMessageWithPublicMetadata& /*input*/) {
   return absl::UnimplementedError("Verify not implemented yet.");
 }
 
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.h b/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.h
index 0f2cd5c..e760182 100644
--- a/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.h
+++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.h
@@ -77,12 +77,12 @@
   absl::StatusOr<std::vector<RSABlindSignatureTokenWithInput>> ProcessResponse(
       const AnonymousTokensSignResponse& response);
 
-  // Method to verify whether a blind token is valid or not.
+  // Method to verify whether an anonymous token is valid or not.
   //
   // Returns OK on a valid token and non-OK otherwise.
-  absl::Status Verify(
-      const RSABlindSignatureToken& token, absl::string_view message,
-      absl::optional<absl::string_view> public_metadata = absl::nullopt);
+  absl::Status Verify(const RSABlindSignaturePublicKey& public_key,
+                      const RSABlindSignatureToken& token,
+                      const PlaintextMessageWithPublicMetadata& input);
 
  private:
   struct BlindingInfo {
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client_test.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client_test.cc
index 84a297f..37d3a01 100644
--- a/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client_test.cc
+++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client_test.cc
@@ -35,6 +35,7 @@
 namespace anonymous_tokens {
 namespace {
 
+using ::testing::SizeIs;
 using quiche::test::StatusIs;
 
 // Returns a fixed public private key pair by calling GetStrongRsaKeys4096().
@@ -159,9 +160,8 @@
 class AnonymousTokensRsaBssaClientTest : public testing::Test {
  protected:
   void SetUp() override {
-    ANON_TOKENS_ASSERT_OK_AND_ASSIGN(auto key_pair, CreateClientTestKey());
-    public_key_ = std::move(key_pair.first);
-    private_key_ = std::move(key_pair.second);
+    ANON_TOKENS_ASSERT_OK_AND_ASSIGN(std::tie(public_key_, private_key_),
+                                     CreateClientTestKey());
     ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
         client_, AnonymousTokensRsaBssaClient::Create(public_key_));
   }
@@ -179,8 +179,8 @@
                                    client_->CreateRequest(input_messages));
   ANON_TOKENS_ASSERT_OK_AND_ASSIGN(AnonymousTokensSignResponse response,
                                    CreateResponse(request, private_key_));
+  EXPECT_THAT(response.anonymous_tokens(), SizeIs(1));
   QUICHE_EXPECT_OK(client_->ProcessResponse(response));
-  EXPECT_EQ(response.anonymous_tokens_size(), 1);
 }
 
 TEST_F(AnonymousTokensRsaBssaClientTest, SuccessMultipleMessages) {
@@ -191,7 +191,7 @@
                                    client_->CreateRequest(input_messages));
   ANON_TOKENS_ASSERT_OK_AND_ASSIGN(AnonymousTokensSignResponse response,
                                    CreateResponse(request, private_key_));
-  EXPECT_EQ(response.anonymous_tokens_size(), 4);
+  EXPECT_THAT(response.anonymous_tokens(), SizeIs(4));
   QUICHE_EXPECT_OK(client_->ProcessResponse(response));
 }
 
@@ -327,6 +327,144 @@
               StatusIs(absl::StatusCode::kInvalidArgument));
 }
 
+class AnonymousTokensRsaBssaClientWithPublicMetadataTest
+    : public testing::Test {
+ protected:
+  void SetUp() override {
+    ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+        std::tie(public_key_, private_key_),
+        CreateClientTestKey("TEST_USE_CASE", /*key_version=*/1,
+                            AT_MESSAGE_MASK_CONCAT,
+                            kRsaMessageMaskSizeInBytes32,
+                            /*enable_public_metadata=*/true));
+    ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+        public_metadata_client_,
+        AnonymousTokensRsaBssaClient::Create(public_key_));
+  }
+
+  RSAPrivateKey private_key_;
+  RSABlindSignaturePublicKey public_key_;
+  std::unique_ptr<AnonymousTokensRsaBssaClient> public_metadata_client_;
+};
+
+TEST_F(AnonymousTokensRsaBssaClientWithPublicMetadataTest,
+       SuccessOneMessageWithPublicMetadata) {
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::vector<PlaintextMessageWithPublicMetadata> input_messages,
+      CreateInput({"message"}, {"md1"}));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignRequest request,
+      public_metadata_client_->CreateRequest(input_messages));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignResponse response,
+      CreateResponse(request, private_key_, /*enable_public_metadata=*/true));
+  EXPECT_THAT(response.anonymous_tokens(), SizeIs(1));
+  QUICHE_EXPECT_OK(public_metadata_client_->ProcessResponse(response));
+}
+
+TEST_F(AnonymousTokensRsaBssaClientWithPublicMetadataTest,
+       FailureWithEmptyPublicMetadata) {
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::vector<PlaintextMessageWithPublicMetadata> input_messages,
+      CreateInput({"message"}, {"md1"}));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignRequest request,
+      public_metadata_client_->CreateRequest(input_messages));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignResponse response,
+      CreateResponse(request, private_key_, /*enable_public_metadata=*/false));
+  EXPECT_THAT(public_metadata_client_->ProcessResponse(response),
+              StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(AnonymousTokensRsaBssaClientWithPublicMetadataTest,
+       FailureWithWrongPublicMetadata) {
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::vector<PlaintextMessageWithPublicMetadata> input_messages,
+      CreateInput({"message"}, {"md1"}));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignRequest request,
+      public_metadata_client_->CreateRequest(input_messages));
+  request.mutable_blinded_tokens(0)->set_public_metadata(
+      "wrong_public_metadata");
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignResponse response,
+      CreateResponse(request, private_key_, /*enable_public_metadata=*/true));
+  EXPECT_THAT(public_metadata_client_->ProcessResponse(response),
+              StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(AnonymousTokensRsaBssaClientWithPublicMetadataTest,
+       FailureWithPublicMetadataSupportOff) {
+  // Create a client with public metadata support disabled.
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(auto key_pair, CreateClientTestKey());
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::unique_ptr<AnonymousTokensRsaBssaClient> non_public_metadata_client,
+      AnonymousTokensRsaBssaClient::Create(key_pair.first));
+
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::vector<PlaintextMessageWithPublicMetadata> input_messages,
+      CreateInput({"message"}, {"md1"}));
+  // Use client_ that does not support public metadata.
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignRequest request,
+      non_public_metadata_client->CreateRequest(input_messages));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignResponse response,
+      CreateResponse(request, private_key_, /*enable_public_metadata=*/true));
+  EXPECT_THAT(non_public_metadata_client->ProcessResponse(response),
+              StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(AnonymousTokensRsaBssaClientWithPublicMetadataTest,
+       SuccessMultipleMessagesWithDistinctPublicMetadata) {
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::vector<PlaintextMessageWithPublicMetadata> input_messages,
+      CreateInput({"message1", "msg2", "anotherMessage", "one_more_message"},
+                  {"md1", "md2", "md3", "md4"}));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignRequest request,
+      public_metadata_client_->CreateRequest(input_messages));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignResponse response,
+      CreateResponse(request, private_key_, /*enable_public_metadata=*/true));
+  EXPECT_THAT(response.anonymous_tokens(), SizeIs(4));
+  QUICHE_EXPECT_OK(public_metadata_client_->ProcessResponse(response));
+}
+
+TEST_F(AnonymousTokensRsaBssaClientWithPublicMetadataTest,
+       SuccessMultipleMessagesWithRepeatedPublicMetadata) {
+  // Create input with repeated public metadata
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::vector<PlaintextMessageWithPublicMetadata> input_messages,
+      CreateInput({"message1", "msg2", "anotherMessage", "one_more_message"},
+                  {"md1", "md2", "md2", "md1"}));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignRequest request,
+      public_metadata_client_->CreateRequest(input_messages));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignResponse response,
+      CreateResponse(request, private_key_, /*enable_public_metadata=*/true));
+  EXPECT_THAT(response.anonymous_tokens(), SizeIs(4));
+  QUICHE_EXPECT_OK(public_metadata_client_->ProcessResponse(response));
+}
+
+TEST_F(AnonymousTokensRsaBssaClientWithPublicMetadataTest,
+       SuccessMultipleMessagesWithEmptyStringPublicMetadata) {
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      std::vector<PlaintextMessageWithPublicMetadata> input_messages,
+      CreateInput({"message1", "msg2", "anotherMessage", "one_more_message"},
+                  {"md1", "", "", "md4"}));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignRequest request,
+      public_metadata_client_->CreateRequest(input_messages));
+  ANON_TOKENS_ASSERT_OK_AND_ASSIGN(
+      AnonymousTokensSignResponse response,
+      CreateResponse(request, private_key_, /*enable_public_metadata=*/true));
+  EXPECT_THAT(response.anonymous_tokens(), SizeIs(4));
+  QUICHE_EXPECT_OK(public_metadata_client_->ProcessResponse(response));
+}
+
 }  // namespace
 }  // namespace anonymous_tokens
 }  // namespace private_membership