Project import generated by Copybara.

GitOrigin-RevId: 0ff286ff293d733f2763ca111b49e0467fe63f26
Change-Id: I26bf2cb36f08fb2e63ff9c6dfcb1d6964d0a03b2
diff --git a/nearby/Cargo.lock b/nearby/Cargo.lock
index dd4f6ff..813de5f 100644
--- a/nearby/Cargo.lock
+++ b/nearby/Cargo.lock
@@ -1377,7 +1377,6 @@
  "np_hkdf",
  "rand",
  "rand_ext",
- "rmp-serde",
  "serde",
  "serde_json",
  "sink",
@@ -1585,12 +1584,6 @@
 ]
 
 [[package]]
-name = "paste"
-version = "1.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
-
-[[package]]
 name = "pkcs8"
 version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1893,28 +1886,6 @@
 ]
 
 [[package]]
-name = "rmp"
-version = "0.8.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20"
-dependencies = [
- "byteorder",
- "num-traits",
- "paste",
-]
-
-[[package]]
-name = "rmp-serde"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a"
-dependencies = [
- "byteorder",
- "rmp",
- "serde",
-]
-
-[[package]]
 name = "rstest"
 version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/cpp/CMakeLists.txt b/nearby/connections/ukey2/ukey2_c_ffi/cpp/CMakeLists.txt
index 165d861..a8b7b9d 100644
--- a/nearby/connections/ukey2/ukey2_c_ffi/cpp/CMakeLists.txt
+++ b/nearby/connections/ukey2/ukey2_c_ffi/cpp/CMakeLists.txt
@@ -21,7 +21,9 @@
 include_directories(
     ${CMAKE_SOURCE_DIR}/ukey2_c_ffi/cpp/)
 
+include(GoogleTest)
 include(ExternalProject)
+
 set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/target/tmp)
 ExternalProject_Add(
     ukey2_c_ffi
@@ -35,11 +37,9 @@
 set(CMAKE_CXX_STANDARD 20)
 
 if(UNIX)
-    add_compile_options(-Wall -Werror -Wextra -Wimplicit-fallthrough -Wextra-semi
+    add_compile_options(-Wall -Wextra -Wimplicit-fallthrough -Wextra-semi
             -Wno-missing-field-initializers -Wno-unused-parameter -Wno-psabi
-            -Wno-unneeded-internal-declaration
-            -Wno-ignored-pragma-optimize
-            -Wno-bitfield-constant-conversion -Wno-deprecated-this-capture -Wshadow
+            -Wshadow
             -Wsign-compare)
 elseif(MSVC)
     add_compile_options(-W4 -MD)
@@ -83,5 +83,4 @@
     )
 endif()
 
-include(GoogleTest)
 gtest_discover_tests(ffi_test)
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock b/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock
index 3f72ae0..b4e08bd 100644
--- a/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock
+++ b/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock
@@ -412,7 +412,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.26",
+ "syn",
 ]
 
 [[package]]
@@ -426,17 +426,6 @@
 ]
 
 [[package]]
-name = "derive-getters"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0122f262bf9c9a367829da84f808d9fb128c10ef283bbe7b0922a77cf07b2747"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
 name = "derive_arbitrary"
 version = "1.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -444,7 +433,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.26",
+ "syn",
 ]
 
 [[package]]
@@ -1151,7 +1140,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.26",
+ "syn",
 ]
 
 [[package]]
@@ -1190,17 +1179,6 @@
 
 [[package]]
 name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
 version = "2.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970"
@@ -1247,7 +1225,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.26",
+ "syn",
 ]
 
 [[package]]
@@ -1310,7 +1288,6 @@
 version = "0.1.0"
 dependencies = [
  "crypto_provider",
- "derive-getters",
  "log",
  "num-bigint",
  "rand",
@@ -1376,7 +1353,7 @@
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.26",
+ "syn",
  "wasm-bindgen-shared",
 ]
 
@@ -1398,7 +1375,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.26",
+ "syn",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
diff --git a/nearby/presence/CMakeLists.txt b/nearby/presence/CMakeLists.txt
index d2a251b..9670c34 100644
--- a/nearby/presence/CMakeLists.txt
+++ b/nearby/presence/CMakeLists.txt
@@ -17,7 +17,7 @@
 project(NearbyProtocol)
 
 # required for designated initializers on MSVC
-set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD 20)
 
 # root directory of repo
 set(BETO_CORE_ROOT ${CMAKE_SOURCE_DIR}/../..)
diff --git a/nearby/presence/np_adv/Cargo.toml b/nearby/presence/np_adv/Cargo.toml
index e502c35..9b576a6 100644
--- a/nearby/presence/np_adv/Cargo.toml
+++ b/nearby/presence/np_adv/Cargo.toml
@@ -39,7 +39,6 @@
 criterion.workspace = true
 crypto_provider_default = { workspace = true, features = ["std", "rustcrypto"] }
 np_ed25519 = { workspace = true, features = ["std"] }
-rmp-serde = "1.1.2"
 sink = { workspace = true, features = ["std"] }
 
 [[bench]]
diff --git a/nearby/presence/np_adv/tests/examples_v1.rs b/nearby/presence/np_adv/tests/examples_v1.rs
index 94b9d75..6e93a3d 100644
--- a/nearby/presence/np_adv/tests/examples_v1.rs
+++ b/nearby/presence/np_adv/tests/examples_v1.rs
@@ -90,13 +90,13 @@
 }
 
 impl IdentityMetadata {
-    /// Serialize this identity metadata to a MsgPack byte-string.
+    /// Serialize this identity metadata to a json byte-string.
     fn to_bytes(&self) -> Vec<u8> {
-        rmp_serde::to_vec(&self).expect("serialization should always succeed")
+        serde_json::to_vec(self).expect("Identity metadata serialization is infallible")
     }
-    /// Attempt to deserialize identity metadata from a MsgPack byte-string.
+    /// Attempt to deserialize identity metadata from a json byte-string.
     fn try_from_bytes(serialized: &[u8]) -> Option<Self> {
-        rmp_serde::from_slice(serialized).ok()
+        serde_json::from_slice(serialized).ok()
     }
 }
 
diff --git a/nearby/presence/np_cpp_ffi/include/nearby_protocol.h b/nearby/presence/np_cpp_ffi/include/nearby_protocol.h
index 1e16eef..2cb410d 100644
--- a/nearby/presence/np_cpp_ffi/include/nearby_protocol.h
+++ b/nearby/presence/np_cpp_ffi/include/nearby_protocol.h
@@ -19,6 +19,8 @@
 #include "absl/strings/str_format.h"
 #include "np_cpp_ffi_types.h"
 
+#include <span>
+
 // This namespace provides a C++ API surface to the Rust nearby protocol
 // implementation. This is a wrapper over the np_ffi::internal namespace defined
 // in the headers np_cpp_ffi_functions.h and np_cpp_ffi_types.h which are
@@ -50,9 +52,10 @@
 namespace nearby_protocol {
 
 // Re-exporting cbindgen generated types which are used in the public API
+using np_ffi::internal::AddCredentialToSlabResult;
 using np_ffi::internal::BooleanActionType;
-using np_ffi::internal::CreateCredentialSlabResultKind;
 using np_ffi::internal::CreateCredentialBookResultKind;
+using np_ffi::internal::CreateCredentialSlabResultKind;
 using np_ffi::internal::DeserializeAdvertisementResultKind;
 using np_ffi::internal::DeserializedV0AdvertisementKind;
 using np_ffi::internal::DeserializedV0IdentityKind;
@@ -67,8 +70,12 @@
 // All of the types defined in this header
 class RawAdvertisementPayload;
 class CredentialBook;
+class CredentialSlab;
 class Deserializer;
 class DeserializeAdvertisementResult;
+class MatchedCredentialData;
+class V0MatchableCredential;
+class V1MatchableCredential;
 
 // V0 Classes
 class DeserializedV0Advertisement;
@@ -156,6 +163,13 @@
   // Creates a new instance of a CredentialSlab, returns the CredentialSlab on
   // success or a Status code on failure
   [[nodiscard]] static absl::StatusOr<CredentialSlab> TryCreate();
+
+  // Adds a V0 credential to the slab
+  [[nodiscard]] absl::Status AddV0Credential(V0MatchableCredential v0_cred);
+
+  // Adds a V1 credential to the slab
+  [[nodiscard]] absl::Status AddV1Credential(V1MatchableCredential v1_cred);
+
 private:
   friend class CredentialBook;
   explicit CredentialSlab(np_ffi::internal::CredentialSlab credential_slab)
@@ -189,7 +203,8 @@
   // returning the CredentialBook on success or a Status code on failure.
   // The passed credential-slab will be deallocated if this operation
   // is successful.
-  [[nodiscard]] static absl::StatusOr<CredentialBook> TryCreateFromSlab(CredentialSlab &slab);
+  [[nodiscard]] static absl::StatusOr<CredentialBook>
+  TryCreateFromSlab(CredentialSlab &slab);
 
 private:
   friend class Deserializer;
@@ -200,6 +215,64 @@
   bool moved_;
 };
 
+// Holds data associated with a specific credential which will be returned to
+// the caller when it is successfully matched with an advertisement.
+class MatchedCredentialData {
+public:
+  // Creates matched credential data from a provided credential_id used to
+  // correlate the data back to its full credential data, and the metadata byte
+  // buffer as copied from the given span over bytes. After calling
+  // this the bytes are copied into the rust code, so the
+  // encrypted_metadata_bytes_buffer can be freed.
+  //
+  // Safety: this is safe if the span is over a valid buffer of bytes. The copy
+  // from the memory address isn't atomic, so concurrent modification of the
+  // array from another thread would cause undefined behavior.
+  [[nodiscard]] MatchedCredentialData(uint32_t cred_id,
+                                      std::span<uint8_t> metadata_bytes);
+
+private:
+  np_ffi::internal::FfiMatchedCredential data_;
+  friend class V0MatchableCredential;
+  friend class V1MatchableCredential;
+};
+
+// Holds the v0 credential data needed by the deserializer to decrypt
+// advertisements, along with some provided matched data that will be returned
+// back to the caller upon a successful credential match.
+class V0MatchableCredential {
+public:
+  // Creates a new V0MatchableCredential from a key seed, its calculated hmac
+  // value and some match data.
+  [[nodiscard]] V0MatchableCredential(
+      std::array<uint8_t, 32> key_seed,
+      std::array<uint8_t, 32> legacy_metadata_key_hmac,
+      MatchedCredentialData matched_credential_data);
+
+private:
+  friend class CredentialSlab;
+  np_ffi::internal::V0MatchableCredential internal_{};
+};
+
+// Holds the v1 credential data needed by the deserializer to decrypt
+// advertisements, along with some provided matched data that will be returned
+// back to the caller upon a successful credential match.
+class V1MatchableCredential {
+public:
+  // Creates a new V1MatchableCredential from key material, its calculated hmac
+  // value and some match data.
+  [[nodiscard]] V1MatchableCredential(
+      std::array<uint8_t, 32> key_seed,
+      std::array<uint8_t, 32> expected_unsigned_metadata_key_hmac,
+      std::array<uint8_t, 32> expected_signed_metadata_key_hmac,
+      std::array<uint8_t, 32> pub_key,
+      MatchedCredentialData matched_credential_data);
+
+private:
+  friend class CredentialSlab;
+  np_ffi::internal::V1MatchableCredential internal_;
+};
+
 // Representation of a buffer of bytes returned from deserialization APIs
 template <size_t N> class ByteBuffer {
 public:
diff --git a/nearby/presence/np_cpp_ffi/nearby_protocol.cc b/nearby/presence/np_cpp_ffi/nearby_protocol.cc
index 106eb77..b6730ef 100644
--- a/nearby/presence/np_cpp_ffi/nearby_protocol.cc
+++ b/nearby/presence/np_cpp_ffi/nearby_protocol.cc
@@ -140,13 +140,47 @@
   return *this;
 }
 
-absl::StatusOr<CredentialBook> CredentialBook::TryCreateFromSlab(CredentialSlab &slab) {
+absl::Status CredentialSlab::AddV0Credential(V0MatchableCredential v0_cred) {
+  assert_panic(!this->moved_);
+  auto result = np_ffi::internal::np_ffi_CredentialSlab_add_v0_credential(
+      this->credential_slab_, v0_cred.internal_);
+  switch (result) {
+  case AddCredentialToSlabResult::Success: {
+    return absl::OkStatus();
+  }
+  case AddCredentialToSlabResult::InvalidHandle: {
+    return absl::InvalidArgumentError(
+        "invalid credential slab handle provided");
+  }
+  }
+}
+
+absl::Status CredentialSlab::AddV1Credential(V1MatchableCredential v1_cred) {
+  assert_panic(!this->moved_);
+  auto result = np_ffi::internal::np_ffi_CredentialSlab_add_v1_credential(
+      this->credential_slab_, v1_cred.internal_);
+  switch (result) {
+  case AddCredentialToSlabResult::Success: {
+    return absl::OkStatus();
+  }
+  case AddCredentialToSlabResult::InvalidHandle: {
+    return absl::InvalidArgumentError(
+        "invalid credential slab handle provided");
+  }
+  }
+}
+
+absl::StatusOr<CredentialBook>
+CredentialBook::TryCreateFromSlab(CredentialSlab &slab) {
   assert_panic(!slab.moved_);
-  auto result = np_ffi::internal::np_ffi_create_credential_book_from_slab(slab.credential_slab_);
+  auto result = np_ffi::internal::np_ffi_create_credential_book_from_slab(
+      slab.credential_slab_);
   auto kind = np_ffi::internal::np_ffi_CreateCredentialBookResult_kind(result);
   switch (kind) {
   case CreateCredentialBookResultKind::Success: {
-    auto book = np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS(result);
+    auto book =
+        np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS(
+            result);
     slab.moved_ = true;
     return CredentialBook(book);
   }
@@ -343,10 +377,11 @@
   }
 }
 
-DeserializedV0IdentityKind LegibleDeserializedV0Advertisement::GetIdentityKind() {
+DeserializedV0IdentityKind
+LegibleDeserializedV0Advertisement::GetIdentityKind() {
   assert_panic(!this->moved_);
-  auto result =
-      np_ffi::internal::np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(
+  auto result = np_ffi::internal::
+      np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(
           legible_v0_advertisement_);
   return result;
 }
@@ -536,4 +571,40 @@
   return ByteBuffer(v1_data_element_.generic._0.payload);
 }
 
+MatchedCredentialData::MatchedCredentialData(
+    uint32_t cred_id, std::span<uint8_t> metadata_bytes) {
+  this->data_ = {cred_id, metadata_bytes.data(), metadata_bytes.size()};
+}
+
+template <typename T, size_t N>
+static void CopyToRawArray(T (&dest)[N], const std::array<T, N> &src) {
+  memcpy(dest, src.data(), sizeof(T) * N);
+}
+
+V0MatchableCredential::V0MatchableCredential(
+    std::array<uint8_t, 32> key_seed,
+    std::array<uint8_t, 32> legacy_metadata_key_hmac,
+    MatchedCredentialData matched_credential_data) {
+  np_ffi::internal::V0DiscoveryCredential discovery_cred{};
+  CopyToRawArray(discovery_cred.key_seed, key_seed);
+  CopyToRawArray(discovery_cred.legacy_metadata_key_hmac,
+                 legacy_metadata_key_hmac);
+  this->internal_ = {discovery_cred, matched_credential_data.data_};
+}
+
+V1MatchableCredential::V1MatchableCredential(
+    std::array<uint8_t, 32> key_seed,
+    std::array<uint8_t, 32> expected_unsigned_metadata_key_hmac,
+    std::array<uint8_t, 32> expected_signed_metadata_key_hmac,
+    std::array<uint8_t, 32> pub_key,
+    MatchedCredentialData matched_credential_data) {
+  np_ffi::internal::V1DiscoveryCredential discovery_cred{};
+  CopyToRawArray(discovery_cred.key_seed, key_seed);
+  CopyToRawArray(discovery_cred.expected_unsigned_metadata_key_hmac,
+                 expected_unsigned_metadata_key_hmac);
+  CopyToRawArray(discovery_cred.expected_signed_metadata_key_hmac,
+                 expected_signed_metadata_key_hmac);
+  CopyToRawArray(discovery_cred.pub_key, pub_key);
+  this->internal_ = {discovery_cred, matched_credential_data.data_};
+}
 } // namespace nearby_protocol
diff --git a/nearby/presence/np_cpp_ffi/sample/main.cc b/nearby/presence/np_cpp_ffi/sample/main.cc
index a02a523..1d273da 100644
--- a/nearby/presence/np_cpp_ffi/sample/main.cc
+++ b/nearby/presence/np_cpp_ffi/sample/main.cc
@@ -81,10 +81,8 @@
   auto v1_byte_string = "20"     // V1 Advertisement header
                         "04"     // Section Header
                         "03"     // Public Identity DE header
-                        "260046" // Length 2 Actions DE
-                        "03"     // Section Header
-                        "03"     // Public Identity DE header
-                        "1505";  // Length 1 Tx Power DE with value 5
+                        "260046";// Length 2 Actions DE
+
   auto v1_bytes = absl::HexStringToBytes(v1_byte_string);
   auto v1_buffer = nearby_protocol::ByteBuffer<255>::CopyFrom(v1_bytes);
   nearby_protocol::RawAdvertisementPayload v1_payload(v1_buffer.value());
diff --git a/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt b/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt
index b5ff838..23d02a4 100644
--- a/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt
+++ b/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt
@@ -17,7 +17,7 @@
         deserialize_result_tests.cc
         deserialize_v0_tests.cc
         deserialize_v1_tests.cc
-	credential_slab_tests.cc
+        credential_slab_tests.cc
         credential_book_tests.cc
         byte_buffer_tests.cc
         np_cpp_test.h
diff --git a/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc b/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc
index 15f262e..7e1a048 100644
--- a/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc
@@ -13,12 +13,13 @@
 // limitations under the License.
 
 #include "nearby_protocol.h"
+#include "np_cpp_test.h"
 #include "shared_test_util.h"
 
 #include "absl/strings/escaping.h"
 #include "gtest/gtest.h"
 
-TEST(ByteBufferTests, ByteBufferMaxLength) {
+TEST_F(NpCppTest, ByteBufferMaxLength) {
   // Each hex byte takes up 2 characters so length 510 string = 255 bytes of hex
   auto str_bytes = generate_hex_string(510);
   auto bytes = absl::HexStringToBytes(str_bytes);
@@ -28,7 +29,7 @@
   ASSERT_EQ(bytes, string);
 }
 
-TEST(ByteBufferTooLarge, ByteBufferInvalidLength) {
+TEST_F(NpCppTest, ByteBufferInvalidLength) {
   // 256 bytes should fail
   auto str_bytes = generate_hex_string(512);
   auto bytes = absl::HexStringToBytes(str_bytes);
@@ -36,26 +37,26 @@
   ASSERT_FALSE(buffer.ok());
 }
 
-TEST(ByteBufferTests, ByteBufferRoundTrip) {
+TEST_F(NpCppTest, ByteBufferRoundTrip) {
   auto bytes = absl::HexStringToBytes("2003031503");
   auto buffer = nearby_protocol::ByteBuffer<255>::CopyFrom(bytes);
   auto string = buffer.value().ToString();
   ASSERT_EQ(bytes, string);
 }
 
-TEST(ByteBufferTests, ByteBufferPayloadWrongSize) {
+TEST_F(NpCppTest, ByteBufferPayloadWrongSize) {
   auto bytes = absl::HexStringToBytes("1111111111111111111111");
   auto buffer = nearby_protocol::ByteBuffer<10>::CopyFrom(bytes);
   ASSERT_FALSE(buffer.ok());
 }
 
-TEST(ByteBufferTests, ByteBufferEmptyString) {
+TEST_F(NpCppTest, ByteBufferEmptyString) {
   auto bytes = absl::HexStringToBytes("");
   auto buffer = nearby_protocol::ByteBuffer<10>::CopyFrom(bytes);
   ASSERT_TRUE(buffer.ok());
 }
 
-TEST(ByteBufferTests, ByteBufferToVector) {
+TEST_F(NpCppTest, ByteBufferToVector) {
   auto bytes = absl::HexStringToBytes("1234567890");
   auto buffer = nearby_protocol::ByteBuffer<100>::CopyFrom(bytes);
   auto vec = buffer.value().ToVector();
@@ -63,7 +64,7 @@
   ASSERT_EQ(vec, expected);
 }
 
-TEST(ByteBufferTests, ByteBufferEndToEndPayloadAsString) {
+TEST_F(NpCppTest, ByteBufferEndToEndPayloadAsString) {
   std::string bytes = absl::HexStringToBytes("2003031503");
   auto buffer = nearby_protocol::ByteBuffer<255>::CopyFrom(bytes);
   ASSERT_TRUE(buffer.ok());
@@ -71,7 +72,9 @@
   nearby_protocol::RawAdvertisementPayload adv(buffer.value());
 
   auto credential_slab = nearby_protocol::CredentialSlab::TryCreate().value();
-  auto credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(credential_slab).value();
+  auto credential_book =
+      nearby_protocol::CredentialBook::TryCreateFromSlab(credential_slab)
+          .value();
   auto str = nearby_protocol::Deserializer::DeserializeAdvertisement(
                  adv, credential_book)
                  .IntoV1()
diff --git a/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc b/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc
index dcaf421..af8fc0d 100644
--- a/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc
@@ -37,7 +37,7 @@
   ASSERT_TRUE(absl::IsResourceExhausted(book3_result.status()));
 }
 
-TEST_F(NpCppTest, TestMoveConstructor) {
+TEST_F(NpCppTest, TestBookMoveConstructor) {
   auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
   auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
   auto deserialize_result =
@@ -69,7 +69,7 @@
                "");
 }
 
-TEST_F(NpCppTest, TestMoveAssignment) {
+TEST_F(NpCppTest, TestBookMoveAssignment) {
   auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
   auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
   auto deserialize_result =
diff --git a/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc b/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc
index f715361..b99ab5e 100644
--- a/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc
@@ -13,8 +13,8 @@
 // limitations under the License.
 
 #include "nearby_protocol.h"
-#include "shared_test_util.h"
 #include "np_cpp_test.h"
+#include "shared_test_util.h"
 
 #include "gtest/gtest.h"
 
@@ -41,16 +41,154 @@
   // credential-book.
   nearby_protocol::CredentialSlab next_slab(std::move(slab));
 
-  auto maybe_book = nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab);
+  auto maybe_book =
+      nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab);
   ASSERT_TRUE(maybe_book.ok());
 
   // Now, both slabs should be moved-out-of, since `TryCreateFromSlab` takes
   // ownership. Verify that this is the case, and attempts to re-use the slabs
   // result in an assert failure.
   ASSERT_DEATH([[maybe_unused]] auto failure =
-                nearby_protocol::CredentialBook::TryCreateFromSlab(slab), //NOLINT(bugprone-use-after-move)
+                   nearby_protocol::CredentialBook::TryCreateFromSlab(
+                       slab), // NOLINT(bugprone-use-after-move)
                "");
+  ASSERT_DEATH(
+      [[maybe_unused]] auto failure =
+          nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab),
+      "");
+}
+
+TEST_F(NpCppTest, TestSlabDestructor) {
+  {
+    auto slab1_result = nearby_protocol::CredentialSlab::TryCreate();
+    ASSERT_TRUE(slab1_result.ok());
+
+    auto slab2_result = nearby_protocol::CredentialSlab::TryCreate();
+    ASSERT_TRUE(slab2_result.ok());
+
+    auto slab3_result = nearby_protocol::CredentialSlab::TryCreate();
+    ASSERT_TRUE(slab3_result.ok());
+
+    auto slab4_result = nearby_protocol::CredentialSlab::TryCreate();
+
+    ASSERT_FALSE(slab4_result.ok());
+    ASSERT_TRUE(absl::IsResourceExhausted(slab4_result.status()));
+  }
+
+  // Now that the above variables have gone out of scope we should verify that
+  // the destructor succeeded in cleaning up those resources
+  auto slab_result = nearby_protocol::CredentialSlab::TryCreate();
+  ASSERT_TRUE(slab_result.ok());
+}
+
+TEST_F(NpCppTest, TestSlabMoveAssignment) {
+  auto slab_result = nearby_protocol::CredentialSlab::TryCreate();
+  ASSERT_TRUE(slab_result.ok());
+
+  // create a second slab
+  auto other_slab_result = nearby_protocol::CredentialSlab::TryCreate();
+  ASSERT_TRUE(other_slab_result.ok());
+
+  // move assignment should override currently assigned slab with new one,
+  // freeing the existing one.
+  auto other_slab = std::move(slab_result.value());
+  auto maybe_book =
+      nearby_protocol::CredentialBook::TryCreateFromSlab(other_slab);
+  ASSERT_TRUE(maybe_book.ok());
+
+  // The old object should now lead to use after moved assert failure
   ASSERT_DEATH([[maybe_unused]] auto failure =
-                nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab),
+                   nearby_protocol::CredentialBook::TryCreateFromSlab(
+                       slab_result.value()), // NOLINT(bugprone-use-after-move)
                "");
+
+  // moving again should still lead to a use after moved assert failure
+  auto another_moved_book = std::move(slab_result.value());
+  ASSERT_DEATH([[maybe_unused]] auto failure =
+                   nearby_protocol::CredentialBook::TryCreateFromSlab(
+                       another_moved_book), // NOLINT(bugprone-use-after-move)
+               "");
+}
+
+TEST_F(NpCppTest, TestAddV0Credential) {
+  auto slab_result = nearby_protocol::CredentialSlab::TryCreate();
+  ASSERT_TRUE(slab_result.ok());
+
+  uint8_t metadata[] = {1, 2, 3};
+  std::span<uint8_t> metadata_span(metadata);
+
+  nearby_protocol::MatchedCredentialData match_data(111, metadata_span);
+  std::array<uint8_t, 32> key_seed {1, 2, 3};
+  std::array<uint8_t, 32> legacy_metadata_key_hmac {1, 2, 3};
+
+  nearby_protocol::V0MatchableCredential v0_cred(
+      key_seed, legacy_metadata_key_hmac, match_data);
+  auto add_result = slab_result.value().AddV0Credential(v0_cred);
+  ASSERT_EQ(add_result, absl::OkStatus());
+}
+
+TEST_F(NpCppTest, TestAddV0CredentialAfterMoved) {
+  auto slab_result = nearby_protocol::CredentialSlab::TryCreate();
+  ASSERT_TRUE(slab_result.ok());
+
+  // creating a book will move the slab
+  auto maybe_book =
+      nearby_protocol::CredentialBook::TryCreateFromSlab(slab_result.value());
+  ASSERT_TRUE(maybe_book.ok());
+
+  uint8_t metadata[] = {1, 2, 3};
+  std::span<uint8_t> metadata_span(metadata);
+  nearby_protocol::MatchedCredentialData match_data(111, metadata_span);
+  std::array<uint8_t, 32> key_seed {1, 2, 3};
+  std::array<uint8_t, 32> legacy_metadata_key_hmac {1, 2, 3};
+  nearby_protocol::V0MatchableCredential v0_cred(
+      key_seed, legacy_metadata_key_hmac, match_data);
+
+  ASSERT_DEATH([[maybe_unused]] auto add_result =
+                   slab_result.value().AddV0Credential(v0_cred);
+               , "");
+}
+
+TEST_F(NpCppTest, TestAddV1Credential) {
+  auto slab_result = nearby_protocol::CredentialSlab::TryCreate();
+  ASSERT_TRUE(slab_result.ok());
+
+  uint8_t metadata[] = {1, 2, 3};
+  std::span<uint8_t> metadata_span(metadata);
+  nearby_protocol::MatchedCredentialData match_data(111, metadata_span);
+  std::array<uint8_t, 32> key_seed {1, 2, 3};
+  std::array<uint8_t, 32> expected_unsigned_metadata_key_hmac {1, 2, 3};
+  std::array<uint8_t, 32> expected_signed_metadata_key_hmac {1, 2, 3};
+  std::array<uint8_t, 32> pub_key {1, 2, 3};
+  nearby_protocol::V1MatchableCredential v1_cred(
+      key_seed, expected_unsigned_metadata_key_hmac,
+      expected_signed_metadata_key_hmac, pub_key, match_data);
+
+  auto add_result = slab_result.value().AddV1Credential(v1_cred);
+  ASSERT_EQ(add_result, absl::OkStatus());
+}
+
+TEST_F(NpCppTest, TestAddV1CredentialAfterMoved) {
+  auto slab_result = nearby_protocol::CredentialSlab::TryCreate();
+  ASSERT_TRUE(slab_result.ok());
+
+  // creating a book will move the slab
+  auto maybe_book =
+      nearby_protocol::CredentialBook::TryCreateFromSlab(slab_result.value());
+  ASSERT_TRUE(maybe_book.ok());
+
+  uint8_t metadata[] = {1, 2, 3};
+  std::span<uint8_t> metadata_span(metadata);
+  nearby_protocol::MatchedCredentialData match_data(111, metadata_span);
+  std::array<uint8_t, 32> key_seed {1, 2, 3};
+  std::array<uint8_t, 32> expected_unsigned_metadata_key_hmac {1, 2, 3};
+  std::array<uint8_t, 32> expected_signed_metadata_key_hmac {1, 2, 3};
+  std::array<uint8_t, 32> pub_key {1, 2, 3};
+  nearby_protocol::V1MatchableCredential v1_cred(
+      key_seed, expected_unsigned_metadata_key_hmac,
+      expected_signed_metadata_key_hmac, pub_key, match_data);
+
+  ASSERT_DEATH([[maybe_unused]] auto add_result =
+                   slab_result.value().AddV1Credential(v1_cred);
+               , "");
 }
diff --git a/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc b/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc
index 54b17ab..3ed2d79 100644
--- a/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc
@@ -15,7 +15,6 @@
 #include "nearby_protocol.h"
 #include "shared_test_util.h"
 #include "np_cpp_test.h"
-
 #include "gtest/gtest.h"
 
 TEST_F(NpCppTest, InvalidCast) {
diff --git a/nearby/src/license.rs b/nearby/src/license.rs
index e479526..387ca27 100644
--- a/nearby/src/license.rs
+++ b/nearby/src/license.rs
@@ -108,5 +108,6 @@
         "**/.editorconfig",
         "**/*.class",
         "**/fuzz/artifacts/**",
+        "**/cmake-build-debug/**",
     ]
 }