Project import generated by Copybara.

GitOrigin-RevId: f70580d4e9be3db690b9b6bdfb8e253a496b0ecd
Change-Id: I88739121e946b84d3268a4fb62731070c76b309d
diff --git a/nearby/presence/np_c_ffi/Cargo.lock b/nearby/presence/np_c_ffi/Cargo.lock
new file mode 100644
index 0000000..ca23800
--- /dev/null
+++ b/nearby/presence/np_c_ffi/Cargo.lock
@@ -0,0 +1,1207 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aead"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
+dependencies = [
+ "bytes",
+ "crypto-common",
+ "generic-array",
+]
+
+[[package]]
+name = "aes"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "aes-gcm-siv"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "polyval",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
+
+[[package]]
+name = "array_ref"
+version = "0.1.0"
+
+[[package]]
+name = "array_view"
+version = "0.1.0"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi 0.1.19",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "base16ct"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bytes"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+
+[[package]]
+name = "cbc"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "cbindgen"
+version = "0.24.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b922faaf31122819ec80c4047cc684c6979a087366c069611e33649bf98e18d"
+dependencies = [
+ "clap",
+ "heck",
+ "indexmap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn 1.0.109",
+ "tempfile",
+ "toml",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "clap"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
+dependencies = [
+ "atty",
+ "bitflags",
+ "clap_lex",
+ "indexmap",
+ "strsim",
+ "termcolor",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "const-oid"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crypto-bigint"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "typenum",
+]
+
+[[package]]
+name = "crypto_provider"
+version = "0.1.0"
+
+[[package]]
+name = "crypto_provider_default"
+version = "0.1.0"
+dependencies = [
+ "cfg-if",
+ "crypto_provider",
+ "crypto_provider_rustcrypto",
+]
+
+[[package]]
+name = "crypto_provider_rustcrypto"
+version = "0.1.0"
+dependencies = [
+ "aead",
+ "aes",
+ "aes-gcm-siv",
+ "cbc",
+ "cfg-if",
+ "crypto_provider",
+ "ctr",
+ "ed25519-dalek",
+ "hkdf",
+ "hmac",
+ "p256",
+ "rand",
+ "rand_chacha",
+ "rand_core",
+ "sec1",
+ "sha2",
+ "subtle",
+ "x25519-dalek",
+]
+
+[[package]]
+name = "ctr"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "4.0.0-rc.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "curve25519-dalek-derive",
+ "digest",
+ "fiat-crypto",
+ "platforms",
+ "rustc_version",
+ "subtle",
+]
+
+[[package]]
+name = "curve25519-dalek-derive"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.23",
+]
+
+[[package]]
+name = "der"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946"
+dependencies = [
+ "const-oid",
+ "zeroize",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "ed25519"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
+dependencies = [
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "2.0.0-rc.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faa8e9049d5d72bfc12acbc05914731b5322f79b5e2f195e9f2d705fca22ab4c"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "rand_core",
+ "sha2",
+]
+
+[[package]]
+name = "elliptic-curve"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
+dependencies = [
+ "base16ct",
+ "crypto-bigint",
+ "digest",
+ "ff",
+ "generic-array",
+ "group",
+ "hkdf",
+ "rand_core",
+ "sec1",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "ff"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
+dependencies = [
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "fiat-crypto"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+ "zeroize",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "group"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "handle_map"
+version = "0.1.0"
+dependencies = [
+ "crypto_provider",
+ "hashbrown 0.14.0",
+ "lock_api",
+ "portable-atomic",
+ "spin 0.9.8",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+]
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+
+[[package]]
+name = "hkdf"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
+dependencies = [
+ "hmac",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "block-padding",
+ "generic-array",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi 0.3.2",
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+dependencies = [
+ "spin 0.5.2",
+]
+
+[[package]]
+name = "ldt"
+version = "0.1.0"
+dependencies = [
+ "crypto_provider",
+ "ldt_tbc",
+]
+
+[[package]]
+name = "ldt_np_adv"
+version = "0.1.0"
+dependencies = [
+ "array_view",
+ "crypto_provider",
+ "ldt",
+ "ldt_tbc",
+ "np_hkdf",
+ "xts_aes",
+]
+
+[[package]]
+name = "ldt_tbc"
+version = "0.1.0"
+dependencies = [
+ "crypto_provider",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.147"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
+
+[[package]]
+name = "lock_api"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "np_adv"
+version = "0.1.0"
+dependencies = [
+ "array_view",
+ "crypto_provider",
+ "lazy_static",
+ "ldt",
+ "ldt_np_adv",
+ "nom",
+ "np_ed25519",
+ "np_hkdf",
+ "rand",
+ "sink",
+ "strum",
+ "strum_macros",
+ "tinyvec",
+ "xts_aes",
+]
+
+[[package]]
+name = "np_c_ffi"
+version = "0.1.0"
+dependencies = [
+ "cbindgen",
+ "crypto_provider_default",
+ "np_ffi_core",
+ "spin 0.9.8",
+]
+
+[[package]]
+name = "np_ed25519"
+version = "0.1.0"
+dependencies = [
+ "array_view",
+ "crypto_provider",
+ "sink",
+ "tinyvec",
+]
+
+[[package]]
+name = "np_ffi_core"
+version = "0.1.0"
+dependencies = [
+ "array_view",
+ "crypto_provider",
+ "crypto_provider_default",
+ "handle_map",
+ "np_adv",
+ "spin 0.9.8",
+]
+
+[[package]]
+name = "np_hkdf"
+version = "0.1.0"
+dependencies = [
+ "crypto_provider",
+ "ldt",
+ "xts_aes",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+
+[[package]]
+name = "os_str_bytes"
+version = "6.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
+
+[[package]]
+name = "p256"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
+dependencies = [
+ "elliptic-curve",
+ "primeorder",
+]
+
+[[package]]
+name = "platforms"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630"
+
+[[package]]
+name = "polyval"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "primeorder"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3"
+dependencies = [
+ "elliptic-curve",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "0.37.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f"
+
+[[package]]
+name = "ryu"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "sec1"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e"
+dependencies = [
+ "base16ct",
+ "der",
+ "generic-array",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+
+[[package]]
+name = "serde"
+version = "1.0.166"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.166"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.23",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "signature"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
+
+[[package]]
+name = "sink"
+version = "0.1.0"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "strum"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
+
+[[package]]
+name = "strum_macros"
+version = "0.24.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+
+[[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.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "fastrand",
+ "redox_syscall",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "typenum"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
+
+[[package]]
+name = "universal-hash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
+dependencies = [
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+
+[[package]]
+name = "x25519-dalek"
+version = "2.0.0-rc.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7fae07da688e17059d5886712c933bb0520f15eff2e09cfa18e30968f4e63a"
+dependencies = [
+ "curve25519-dalek",
+ "rand_core",
+]
+
+[[package]]
+name = "xts_aes"
+version = "0.1.0"
+dependencies = [
+ "array_ref",
+ "crypto_provider",
+ "ldt_tbc",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
diff --git a/nearby/presence/np_c_ffi/Cargo.toml b/nearby/presence/np_c_ffi/Cargo.toml
new file mode 100644
index 0000000..1dd9f32
--- /dev/null
+++ b/nearby/presence/np_c_ffi/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "np_c_ffi"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+# TODO: We need to make this configurable for this crate and for np_ffi below it.
+crypto_provider_default = {path = "../../crypto/crypto_provider_default", features = ["rustcrypto"]}
+np_ffi_core = {path = "../np_ffi_core"}
+spin = "0.9.8"
+
+[build-dependencies]
+cbindgen = "0.24.5"
+
+[lib]
+# boringssl and bssl-sys are built as a static lib, so we need to as well
+crate-type = ["staticlib"]
\ No newline at end of file
diff --git a/nearby/presence/np_c_ffi/build.rs b/nearby/presence/np_c_ffi/build.rs
new file mode 100644
index 0000000..b282709
--- /dev/null
+++ b/nearby/presence/np_c_ffi/build.rs
@@ -0,0 +1,63 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use cbindgen::ItemType::*;
+use std::vec;
+
+const C_CONFIG: &str = "cbindgen_configs/c_config.toml";
+const C_OUTPUT_HEADER_FILE: &str = "include/c/np_c_ffi.h";
+
+const CPP_CONFIG: &str = "cbindgen_configs/cpp_config.toml";
+const CPP_INCLUDE_DIR_BASE: &str = "include/cpp/";
+const CPP_PUBLIC_HEADER_FILE: &str = "np_cpp_ffi_types.h";
+const CPP_INTERNAL_HEADER_FILE: &str = "np_cpp_ffi_functions.h";
+
+fn main() {
+    let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
+
+    let config_file = format!("{crate_dir}/{C_CONFIG}");
+    let config = cbindgen::Config::from_file(config_file).expect("Config file should exist");
+    generate_c_header(&crate_dir, config);
+
+    let config_file = format!("{crate_dir}/{CPP_CONFIG}");
+    let config = cbindgen::Config::from_file(config_file).expect("Config file should exist");
+    generate_private_cpp_header(&crate_dir, config.clone());
+    generate_public_cpp_header(&crate_dir, config);
+}
+
+fn generate_c_header(crate_dir: &String, config: cbindgen::Config) {
+    let output_header_file = format!("{crate_dir}/{C_OUTPUT_HEADER_FILE}");
+    generate_header(&output_header_file, crate_dir, config);
+}
+
+fn generate_private_cpp_header(crate_dir: &String, mut config: cbindgen::Config) {
+    config.export.item_types.append(&mut vec![Functions]);
+    config.includes.push(CPP_PUBLIC_HEADER_FILE.to_string());
+    let output_header_file =
+        format!("{crate_dir}/{CPP_INCLUDE_DIR_BASE}/{CPP_INTERNAL_HEADER_FILE}");
+    generate_header(&output_header_file, crate_dir, config);
+}
+
+fn generate_public_cpp_header(crate_dir: &String, mut config: cbindgen::Config) {
+    config.export.item_types.append(&mut vec![Enums, Structs]);
+    let output_header_file = format!("{crate_dir}/{CPP_INCLUDE_DIR_BASE}/{CPP_PUBLIC_HEADER_FILE}");
+    generate_header(&output_header_file, crate_dir, config);
+}
+
+fn generate_header(output_file: &String, crate_dir: &String, config: cbindgen::Config) {
+    let _ = cbindgen::generate_with_config(crate_dir, config)
+        .map_err(|e| println!("cargo:warning=ERROR: {e}"))
+        .expect("c header file generation failed")
+        .write_to_file(output_file);
+}
diff --git a/nearby/presence/np_c_ffi/cbindgen_configs/c_config.toml b/nearby/presence/np_c_ffi/cbindgen_configs/c_config.toml
new file mode 100644
index 0000000..88483b0
--- /dev/null
+++ b/nearby/presence/np_c_ffi/cbindgen_configs/c_config.toml
@@ -0,0 +1,50 @@
+language = "C"
+
+# Instead go through CPP generated header
+cpp_compat = false
+
+style = "type"
+header = """
+/*
+ Copyright 2023 Google LLC
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+"""
+pragma_once = true
+autogen_warning = """
+/*
+ WARNING: this file is autogenerated by cbindgen. Don't modify this manually.
+ Additionally, you should _not_ rely upon the layouts of the generated
+ structs and unions if you want your code to be forward-compatible,
+ unless a given type explicitly states in its documentation that it has
+ a guaranteed forward-compatible layout.
+ Instead, you should use _only_ the provided exported function symbols.
+*/"""
+include_version = true
+
+sort_by = "None" # Use order specified in Rust
+
+[export]
+# Prefix to add before the name of every item
+prefix = "np_ffi_"
+
+[enum]
+rename_variants = "QualifiedScreamingSnakeCase"
+
+[parse]
+parse_deps = true
+include = ["np_c_ffi", "np_ffi_core"]
+
+[parse.expand]
+crates = ["np_ffi_core"]
+default_features = true
diff --git a/nearby/presence/np_c_ffi/cbindgen_configs/cpp_config.toml b/nearby/presence/np_c_ffi/cbindgen_configs/cpp_config.toml
new file mode 100644
index 0000000..5a2ba2a
--- /dev/null
+++ b/nearby/presence/np_c_ffi/cbindgen_configs/cpp_config.toml
@@ -0,0 +1,44 @@
+language = "C++"
+
+style = "type"
+header = """
+/*
+ Copyright 2023 Google LLC
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+"""
+pragma_once = true
+autogen_warning = """
+/*
+ WARNING: this file is autogenerated by cbindgen. Don't modify this manually.
+ Additionally, you should _not_ rely upon the layouts of the generated
+ structs and unions if you want your code to be forward-compatible,
+ unless a given type explicitly states in its documentation that it has
+ a guaranteed forward-compatible layout.
+ Instead, you should use _only_ the provided exported function symbols.
+*/"""
+include_version = true
+namespaces = ["np_ffi", "internal"]
+
+sort_by = "None" # Use order specified in Rust
+
+[enum]
+rename_variants = "None"
+
+[parse]
+parse_deps = true
+include = ["np_c_ffi", "np_ffi_core"]
+
+[parse.expand]
+crates = ["np_ffi_core"]
+default_features = true
diff --git a/nearby/presence/np_c_ffi/include/c/np_c_ffi.h b/nearby/presence/np_c_ffi/include/c/np_c_ffi.h
new file mode 100644
index 0000000..03e5821
--- /dev/null
+++ b/nearby/presence/np_c_ffi/include/c/np_c_ffi.h
@@ -0,0 +1,890 @@
+/*
+ Copyright 2023 Google LLC
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+
+#pragma once
+
+/* Generated with cbindgen:0.24.5 */
+
+/*
+ WARNING: this file is autogenerated by cbindgen. Don't modify this manually.
+ Additionally, you should _not_ rely upon the layouts of the generated
+ structs and unions if you want your code to be forward-compatible,
+ unless a given type explicitly states in its documentation that it has
+ a guaranteed forward-compatible layout.
+ Instead, you should use _only_ the provided exported function symbols.
+*/
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/**
+ * The possible boolean action types which can be present in an Actions data element
+ */
+enum np_ffi_BooleanActionType {
+  NP_FFI_BOOLEAN_ACTION_TYPE_ACTIVE_UNLOCK = 8,
+  NP_FFI_BOOLEAN_ACTION_TYPE_NEARBY_SHARE = 9,
+  NP_FFI_BOOLEAN_ACTION_TYPE_INSTANT_TETHERING = 10,
+  NP_FFI_BOOLEAN_ACTION_TYPE_PHONE_HUB = 11,
+  NP_FFI_BOOLEAN_ACTION_TYPE_PRESENCE_MANAGER = 12,
+  NP_FFI_BOOLEAN_ACTION_TYPE_FINDER = 13,
+  NP_FFI_BOOLEAN_ACTION_TYPE_FAST_PAIR_SASS = 14,
+};
+typedef uint8_t np_ffi_BooleanActionType;
+
+/**
+ * Discriminant for `CreateCredentialBookResult`
+ */
+enum np_ffi_CreateCredentialBookResultKind {
+  /**
+   * There was no space left to create a new credential book
+   */
+  NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_NO_SPACE_LEFT = 0,
+  /**
+   * We created a new credential book behind the given handle.
+   * The associated payload may be obtained via
+   * `CreateCredentialBookResult#into_success()`.
+   */
+  NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_SUCCESS = 1,
+};
+typedef uint8_t np_ffi_CreateCredentialBookResultKind;
+
+/**
+ * A result-type enum which tells the caller whether/not a deallocation
+ * succeeded or failed due to the requested handle not being present.
+ */
+typedef enum {
+  /**
+   * The requested handle to deallocate was not present in the map
+   */
+  NP_FFI_DEALLOCATE_RESULT_NOT_PRESENT = 0,
+  /**
+   * The object behind the handle was successfully deallocated
+   */
+  NP_FFI_DEALLOCATE_RESULT_SUCCESS = 1,
+} np_ffi_DeallocateResult;
+
+/**
+ * Discriminant for `DeserializeAdvertisementResult`.
+ */
+enum np_ffi_DeserializeAdvertisementResultKind {
+  /**
+   * Deserializing the advertisement failed, for some reason or another.
+   */
+  NP_FFI_DESERIALIZE_ADVERTISEMENT_RESULT_KIND_ERROR = 0,
+  /**
+   * The advertisement was correctly deserialized, and it's a V0 advertisement.
+   * `DeserializeAdvertisementResult#into_v0()` is the corresponding cast
+   * to the associated enum variant.
+   */
+  NP_FFI_DESERIALIZE_ADVERTISEMENT_RESULT_KIND_V0 = 1,
+  /**
+   * The advertisement was correctly deserialized, and it's a V1 advertisement.
+   * `DeserializeAdvertisementResult#into_v1()` is the corresponding cast
+   * to the associated enum variant.
+   */
+  NP_FFI_DESERIALIZE_ADVERTISEMENT_RESULT_KIND_V1 = 2,
+};
+typedef uint8_t np_ffi_DeserializeAdvertisementResultKind;
+
+/**
+ * Discriminant for possible results of V0 advertisement deserialization
+ */
+enum np_ffi_DeserializedV0AdvertisementKind {
+  /**
+   * The deserialized V0 advertisement was legible.
+   * The associated payload may be obtained via
+   * `DeserializedV0Advertisement#into_legible`.
+   */
+  NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_KIND_LEGIBLE = 0,
+  /**
+   * The deserialized V0 advertisement is illegible,
+   * likely meaning that the receiver does not hold
+   * the proper credentials to be able to read
+   * the received advertisement.
+   */
+  NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_KIND_NO_MATCHING_CREDENTIALS = 1,
+};
+typedef uint8_t np_ffi_DeserializedV0AdvertisementKind;
+
+/**
+ * Represents deserialized information about the V0 identity utilized
+ * by a deserialized V0 advertisement
+ */
+typedef enum {
+  NP_FFI_DESERIALIZED_V0_IDENTITY_PLAINTEXT,
+  NP_FFI_DESERIALIZED_V0_IDENTITY_DECRYPTED,
+} np_ffi_DeserializedV0Identity;
+
+/**
+ * Discriminant for `DeserializedV0Identity`.
+ */
+enum np_ffi_DeserializedV0IdentityKind {
+  /**
+   * The deserialized identity was a plaintext identity.
+   */
+  NP_FFI_DESERIALIZED_V0_IDENTITY_KIND_PLAINTEXT = 0,
+  /**
+   * The deserialized identity was some decrypted identity.
+   */
+  NP_FFI_DESERIALIZED_V0_IDENTITY_KIND_DECRYPTED = 1,
+};
+typedef uint8_t np_ffi_DeserializedV0IdentityKind;
+
+/**
+ * Discriminant for `DeserializedV1Identity`.
+ */
+enum np_ffi_DeserializedV1IdentityKind {
+  /**
+   * The deserialized v1 identity was plaintext
+   */
+  NP_FFI_DESERIALIZED_V1_IDENTITY_KIND_PLAINTEXT = 0,
+  /**
+   * The deserialized v1 identity corresponded
+   * to some kind of decrypted identity.
+   */
+  NP_FFI_DESERIALIZED_V1_IDENTITY_KIND_DECRYPTED = 1,
+};
+typedef uint8_t np_ffi_DeserializedV1IdentityKind;
+
+/**
+ * Discriminant of `GetV0DEResult`.
+ */
+enum np_ffi_GetV0DEResultKind {
+  /**
+   * The attempt to get the DE succeeded.
+   * The associated payload may be obtained via
+   * `GetV0DEResult#into_success`.
+   */
+  NP_FFI_GET_V0DE_RESULT_KIND_SUCCESS = 0,
+  /**
+   * The attempt to get the DE failed,
+   * possibly due to the requested index being
+   * out-of-bounds or due to the advertisement
+   * having been previously deallocated.
+   */
+  NP_FFI_GET_V0DE_RESULT_KIND_ERROR = 1,
+};
+typedef uint8_t np_ffi_GetV0DEResultKind;
+
+/**
+ * Discriminant for the `GetV1DEResult` enum.
+ */
+enum np_ffi_GetV1DEResultKind {
+  /**
+   * Attempting to get the DE at the given position failed,
+   * possibly due to the index being out-of-bounds or due
+   * to the whole advertisement having been previously deallocated.
+   */
+  NP_FFI_GET_V1DE_RESULT_KIND_ERROR = 0,
+  /**
+   * Attempting to get the DE at the given position succeeded.
+   * The underlying DE may be extracted with `GetV1DEResult#into_success`.
+   */
+  NP_FFI_GET_V1DE_RESULT_KIND_SUCCESS = 1,
+};
+typedef uint8_t np_ffi_GetV1DEResultKind;
+
+/**
+ * Discriminant for `GetV1SectionResult`
+ */
+enum np_ffi_GetV1SectionResultKind {
+  /**
+   * The attempt to get the section failed,
+   * possibly due to the section index being
+   * out-of-bounds or due to the underlying
+   * advertisement having already been deallocated.
+   */
+  NP_FFI_GET_V1_SECTION_RESULT_KIND_ERROR = 0,
+  /**
+   * The attempt to get the section succeeded.
+   * The wrapped section may be obtained via
+   * `GetV1SectionResult#into_success`.
+   */
+  NP_FFI_GET_V1_SECTION_RESULT_KIND_SUCCESS = 1,
+};
+typedef uint8_t np_ffi_GetV1SectionResultKind;
+
+/**
+ * Structure for categorized reasons for why a NP C FFI call may
+ * be panicking.
+ */
+enum np_ffi_PanicReason {
+  /**
+   * Some enum cast to a variant failed. Utilized
+   * for failed enum casts of all enums.
+   *
+   * (That is, this is the catch-all panic reason for enum
+   * casts where there is not a more specific reason
+   * in some other variant of this enum.)
+   */
+  NP_FFI_PANIC_REASON_ENUM_CAST_FAILED = 0,
+  /**
+   * The panic handler is used to assert conditions are true to avoid programmer errors.
+   * If a failed assert condition is hit, this panic handler is invoked with this reason.
+   */
+  NP_FFI_PANIC_REASON_ASSERT_FAILED = 1,
+  /**
+   * Error returned if action bits inside of a V0Actions struct are invalid. If the struct was
+   * created by this deserializer, the bits will always be valid, they are only invalid if
+   * a user reaches in and changes them to something invalid.
+   */
+  NP_FFI_PANIC_REASON_INVALID_ACTION_BITS = 2,
+};
+typedef uint8_t np_ffi_PanicReason;
+
+/**
+ * Discriminant for `V0DataElement`.
+ */
+enum np_ffi_V0DataElementKind {
+  /**
+   * A transmission Power (Tx Power) data-element.
+   * The associated payload may be obtained via
+   * `V0DataElement#into_tx_power`.
+   */
+  NP_FFI_V0_DATA_ELEMENT_KIND_TX_POWER = 0,
+  /**
+   * The Actions data-element.
+   * The associated payload may be obtained via
+   * `V0DataElement#into_actions`.
+   */
+  NP_FFI_V0_DATA_ELEMENT_KIND_ACTIONS = 1,
+};
+typedef uint8_t np_ffi_V0DataElementKind;
+
+/**
+ *A `#[repr(C)]` handle to a value of type `super::CredentialBookInternals`.
+ */
+typedef struct {
+  uint64_t handle_id;
+} np_ffi_CredentialBook;
+
+/**
+ * Result type for `create_credential_book`
+ */
+enum np_ffi_CreateCredentialBookResult_Tag {
+  NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_NO_SPACE_LEFT = 0,
+  NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_SUCCESS = 1,
+};
+typedef uint8_t np_ffi_CreateCredentialBookResult_Tag;
+
+typedef union {
+  np_ffi_CreateCredentialBookResult_Tag tag;
+  struct {
+    np_ffi_CreateCredentialBookResult_Tag success_tag;
+    np_ffi_CredentialBook success;
+  };
+} np_ffi_CreateCredentialBookResult;
+
+/**
+ *A `#[repr(C)]` handle to a value of type `super::V0PayloadInternals`.
+ */
+typedef struct {
+  uint64_t handle_id;
+} np_ffi_V0Payload;
+
+/**
+ * Represents a deserialized V0 advertisement whose DE contents may be read
+ */
+typedef struct {
+  uint8_t num_des;
+  np_ffi_V0Payload payload;
+  np_ffi_DeserializedV0Identity identity;
+} np_ffi_LegibleDeserializedV0Advertisement;
+
+/**
+ * Represents a deserialized V0 advertisement
+ */
+typedef enum {
+  NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_LEGIBLE,
+  NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_NO_MATCHING_CREDENTIALS,
+} np_ffi_DeserializedV0Advertisement_Tag;
+
+typedef struct {
+  np_ffi_DeserializedV0Advertisement_Tag tag;
+  union {
+    struct {
+      np_ffi_LegibleDeserializedV0Advertisement legible;
+    };
+  };
+} np_ffi_DeserializedV0Advertisement;
+
+/**
+ *A `#[repr(C)]` handle to a value of type `super::LegibleV1SectionsInternals`.
+ */
+typedef struct {
+  uint64_t handle_id;
+} np_ffi_LegibleV1Sections;
+
+/**
+ * Representation of a deserialized V1 advertisement
+ */
+typedef struct {
+  uint8_t num_legible_sections;
+  uint8_t num_undecryptable_sections;
+  np_ffi_LegibleV1Sections legible_sections;
+} np_ffi_DeserializedV1Advertisement;
+
+/**
+ * The result of calling `np_ffi_deserialize_advertisement`.
+ * Must be explicitly deallocated after use with
+ * a corresponding `np_ffi_deallocate_deserialize_advertisement_result`
+ */
+enum np_ffi_DeserializeAdvertisementResult_Tag {
+  /**
+   * Deserializing the advertisement failed, for some reason or another.
+   * `DeserializeAdvertisementResultKind::Error` is the associated enum tag.
+   */
+  NP_FFI_DESERIALIZE_ADVERTISEMENT_RESULT_ERROR,
+  /**
+   * The advertisement was correctly deserialized, and it's a V0 advertisement.
+   * `DeserializeAdvertisementResultKind::V0` is the associated enum tag.
+   */
+  NP_FFI_DESERIALIZE_ADVERTISEMENT_RESULT_V0,
+  /**
+   * The advertisement was correctly deserialized, and it's a V1 advertisement.
+   * `DeserializeAdvertisementResultKind::V1` is the associated enum tag.
+   */
+  NP_FFI_DESERIALIZE_ADVERTISEMENT_RESULT_V1,
+};
+typedef uint8_t np_ffi_DeserializeAdvertisementResult_Tag;
+
+typedef union {
+  np_ffi_DeserializeAdvertisementResult_Tag tag;
+  struct {
+    np_ffi_DeserializeAdvertisementResult_Tag v0_tag;
+    np_ffi_DeserializedV0Advertisement v0;
+  };
+  struct {
+    np_ffi_DeserializeAdvertisementResult_Tag v1_tag;
+    np_ffi_DeserializedV1Advertisement v1;
+  };
+} np_ffi_DeserializeAdvertisementResult;
+
+/**
+ * A byte-string with a maximum size of N,
+ * where only the first `len` bytes are considered
+ * to contain the actual payload. N is only
+ * permitted to be between 0 and 255.
+ */
+typedef struct {
+  uint8_t len;
+  uint8_t bytes[255];
+} np_ffi_ByteBuffer_255;
+
+/**
+ * Represents the raw contents of the service payload data
+ * under the Nearby Presence service UUID
+ */
+typedef struct {
+  np_ffi_ByteBuffer_255 bytes;
+} np_ffi_RawAdvertisementPayload;
+
+/**
+ * Representation of a transmission power,
+ * as used for the Tx Power DE in V0 and V1.
+ */
+typedef struct {
+  int8_t tx_power;
+} np_ffi_TxPower;
+
+/**
+ * The bitfield data of a VOActions data element
+ */
+typedef struct {
+  uint32_t bitfield;
+} np_ffi_V0ActionBits;
+
+/**
+ * Representation of the Actions DE in V0.
+ */
+typedef enum {
+  /**
+   * A set of action bits which were present in a plaintext identity advertisement
+   */
+  NP_FFI_V0_ACTIONS_PLAINTEXT,
+  /**
+   * A set of action bits which were present in a encrypted identity advertisement
+   */
+  NP_FFI_V0_ACTIONS_ENCRYPTED,
+} np_ffi_V0Actions_Tag;
+
+typedef struct {
+  np_ffi_V0Actions_Tag tag;
+  union {
+    struct {
+      np_ffi_V0ActionBits plaintext;
+    };
+    struct {
+      np_ffi_V0ActionBits encrypted;
+    };
+  };
+} np_ffi_V0Actions;
+
+/**
+ * Representation of a V0 data element.
+ */
+typedef enum {
+  NP_FFI_V0_DATA_ELEMENT_TX_POWER,
+  NP_FFI_V0_DATA_ELEMENT_ACTIONS,
+} np_ffi_V0DataElement_Tag;
+
+typedef struct {
+  np_ffi_V0DataElement_Tag tag;
+  union {
+    struct {
+      np_ffi_TxPower tx_power;
+    };
+    struct {
+      np_ffi_V0Actions actions;
+    };
+  };
+} np_ffi_V0DataElement;
+
+/**
+ * The result of `V0Payload#get_de`.
+ */
+typedef enum {
+  NP_FFI_GET_V0DE_RESULT_SUCCESS,
+  NP_FFI_GET_V0DE_RESULT_ERROR,
+} np_ffi_GetV0DEResult_Tag;
+
+typedef struct {
+  np_ffi_GetV0DEResult_Tag tag;
+  union {
+    struct {
+      np_ffi_V0DataElement success;
+    };
+  };
+} np_ffi_GetV0DEResult;
+
+/**
+ * Handle to a deserialized V1 section
+ */
+typedef struct {
+  np_ffi_LegibleV1Sections legible_sections_handle;
+  uint8_t legible_section_index;
+  uint8_t num_des;
+  np_ffi_DeserializedV1IdentityKind identity_tag;
+} np_ffi_DeserializedV1Section;
+
+/**
+ * The result of attempting to get a particular V1 section
+ * from its' index within the list of legible sections
+ * via `DeserializedV1Advertisement::get_section`.
+ */
+typedef enum {
+  NP_FFI_GET_V1_SECTION_RESULT_ERROR,
+  NP_FFI_GET_V1_SECTION_RESULT_SUCCESS,
+} np_ffi_GetV1SectionResult_Tag;
+
+typedef struct {
+  np_ffi_GetV1SectionResult_Tag tag;
+  union {
+    struct {
+      np_ffi_DeserializedV1Section success;
+    };
+  };
+} np_ffi_GetV1SectionResult;
+
+/**
+ * Representation of the data-element type tag
+ * of a V1 data element.
+ */
+typedef struct {
+  uint32_t code;
+} np_ffi_V1DEType;
+
+/**
+ * A byte-string with a maximum size of N,
+ * where only the first `len` bytes are considered
+ * to contain the actual payload. N is only
+ * permitted to be between 0 and 255.
+ */
+typedef struct {
+  uint8_t len;
+  uint8_t bytes[127];
+} np_ffi_ByteBuffer_127;
+
+/**
+ * FFI-transmissible representation of a generic V1 data-element.
+ * This representation is stable, and so you may directly
+ * reference this struct's fields if you wish.
+ */
+typedef struct {
+  /**
+   * The DE type code of this generic data-element.
+   */
+  np_ffi_V1DEType de_type;
+  /**
+   * The raw data-element byte payload, up to
+   * 127 bytes in length.
+   */
+  np_ffi_ByteBuffer_127 payload;
+} np_ffi_GenericV1DataElement;
+
+/**
+ * FFI-transmissible representation of a V1 data-element
+ */
+typedef enum {
+  /**
+   * A "generic" V1 data-element, for which we have no
+   * particular information about its schema (just
+   * a DE type code and a byte payload.)
+   */
+  NP_FFI_V1_DATA_ELEMENT_GENERIC,
+} np_ffi_V1DataElement_Tag;
+
+typedef struct {
+  np_ffi_V1DataElement_Tag tag;
+  union {
+    struct {
+      np_ffi_GenericV1DataElement generic;
+    };
+  };
+} np_ffi_V1DataElement;
+
+/**
+ * Represents the result of the `DeserializedV1Section#get_de` operation.
+ */
+typedef enum {
+  NP_FFI_GET_V1DE_RESULT_ERROR,
+  NP_FFI_GET_V1DE_RESULT_SUCCESS,
+} np_ffi_GetV1DEResult_Tag;
+
+typedef struct {
+  np_ffi_GetV1DEResult_Tag tag;
+  union {
+    struct {
+      np_ffi_V1DataElement success;
+    };
+  };
+} np_ffi_GetV1DEResult;
+
+/**
+ * Overrides the global panic handler to be used when NP C FFI calls panic.
+ * This method will only have an effect on the global panic-handler
+ * the first time it's called, and this method will return `true`
+ * to indicate that the panic handler was successfully set.
+ * All subsequent calls to this method
+ * will simply ignore the argument and return `false`.
+ *
+ * If the passed function pointer is non-null,
+ * then we will call it upon every panic,
+ * followed by the default panicking behavior for
+ * the platform (in the case where the user-specified
+ * function does not terminate or hang the running process.)
+ *
+ * Otherwise, we will resort to the
+ * default panicking behavior for the system, which
+ * is a printed stack trace followed by an abort
+ * when this crate is compiled with `std`,
+ * but a bare `loop { }` when this crate is compiled without.
+ */
+bool np_ffi_global_config_panic_handler(void (*handler)(np_ffi_PanicReason));
+
+/**
+ * Sets an override to the number of shards to employ in the NP FFI's
+ * internal handle-maps, which places an upper bound on the number
+ * of writing threads which may make progress at any one time
+ * when concurrently accessing handles of the same type.
+ *
+ * By default, this value will be set to 16, or in `std` environments,
+ * the minimum of 16 and the number of available hardware threads.
+ * A shard value override of zero will be interpreted the same
+ * as this default.
+ *
+ * Setting this value will have no effect if the handle-maps for the
+ * API have already begun being used by the client code, and any
+ * values set will take effect upon the first usage of _any_ non-`np_ffi_global_config_set`
+ * API call.
+ */
+void np_ffi_global_config_set_num_shards(uint8_t num_shards);
+
+/**
+ * Sets the maximum number of active handles to credential books
+ * which may be active at any one time.
+ * Default value: Max value.
+ * Max value: `u32::MAX - 1`.
+ *
+ * Useful for bounding the maximum memory used by the client application
+ * on credential books in constrained-memory environments.
+ *
+ * Setting this value will have no effect if the handle-maps for the
+ * API have already begun being used by the client code, and any
+ * values set will take effect upon the first usage of any API
+ * call utilizing credential books.
+ */
+void np_ffi_global_config_set_max_num_credential_books(uint32_t max_num_credential_books);
+
+/**
+ * Sets the maximum number of active handles to deserialized v0
+ * advertisements which may be active at any one time.
+ *
+ * Useful for bounding the maximum memory used by the client application
+ * on v0 advertisements in constrained-memory environments.
+ *
+ * Default value: Max value.
+ * Max value: `u32::MAX - 1`.
+ *
+ * Setting this value will have no effect if the handle-maps for the
+ * API have already begun being used by the client code, and any
+ * values set will take effect upon the first usage of any API
+ * call which references or returns a deserialized V0 advertisement.
+ */
+void np_ffi_global_config_set_max_num_deserialized_v0_advertisements(uint32_t max_num_deserialized_v0_advertisements);
+
+/**
+ * Sets the maximum number of active handles to deserialized v1
+ * advertisements which may be active at any one time.
+ *
+ * Useful for bounding the maximum memory used by the client application
+ * on v1 advertisements in constrained-memory environments.
+ *
+ * Default value: Max value.
+ * Max value: `u32::MAX - 1`.
+ *
+ * Setting this value will have no effect if the handle-maps for the
+ * API have already begun being used by the client code, and any
+ * values set will take effect upon the first usage of any API
+ * call which references or returns a deserialized V1 advertisement.
+ */
+void np_ffi_global_config_set_max_num_deserialized_v1_advertisements(uint32_t max_num_deserialized_v1_advertisements);
+
+/**
+ * Allocates a new credential-book, returning a handle to the created object
+ */
+np_ffi_CreateCredentialBookResult np_ffi_create_credential_book(void);
+
+/**
+ * Gets the tag of a `CreateCredentialBookResult` tagged enum.
+ */
+np_ffi_CreateCredentialBookResultKind np_ffi_CreateCredentialBookResult_kind(np_ffi_CreateCredentialBookResult result);
+
+/**
+ * Casts a `CreateCredentialBookResult` to the `SUCCESS` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_CredentialBook np_ffi_CreateCredentialBookResult_into_SUCCESS(np_ffi_CreateCredentialBookResult result);
+
+/**
+ * Deallocates a credential-book by its handle
+ */
+np_ffi_DeallocateResult np_ffi_deallocate_credential_book(np_ffi_CredentialBook credential_book);
+
+/**
+ * Attempts to deserialize an advertisement with the given service-data
+ * payload (presumed to be under the NP service UUID) using credentials
+ * pulled from the given credential-book.
+ */
+np_ffi_DeserializeAdvertisementResult np_ffi_deserialize_advertisement(np_ffi_RawAdvertisementPayload adv_payload,
+                                                                       np_ffi_CredentialBook credential_book);
+
+/**
+ * Gets the tag of a `DeserializeAdvertisementResult` tagged-union.
+ */
+np_ffi_DeserializeAdvertisementResultKind np_ffi_DeserializeAdvertisementResult_kind(np_ffi_DeserializeAdvertisementResult result);
+
+/**
+ * Casts a `DeserializeAdvertisementResult` to the `V0` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_DeserializedV0Advertisement np_ffi_DeserializeAdvertisementResult_into_V0(np_ffi_DeserializeAdvertisementResult result);
+
+/**
+ * Casts a `DeserializeAdvertisementResult` to the `V1` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_DeserializedV1Advertisement np_ffi_DeserializeAdvertisementResult_into_V1(np_ffi_DeserializeAdvertisementResult result);
+
+/**
+ * Deallocates any internal data referenced by a `DeserializeAdvertisementResult`. This should only
+ * be used if into_V0 or into_V1, have not been called yet as it shares the same underlying
+ * resource.
+ */
+np_ffi_DeallocateResult np_ffi_deallocate_deserialize_advertisement_result(np_ffi_DeserializeAdvertisementResult result);
+
+/**
+ * Deallocates any internal data referenced by a `DeserializedV0Advertisement`
+ */
+np_ffi_DeallocateResult np_ffi_deallocate_deserialized_V0_advertisement(np_ffi_DeserializedV0Advertisement adv);
+
+/**
+ * Deallocates any internal data referenced by a `DeserializedV1Advertisement`
+ */
+np_ffi_DeallocateResult np_ffi_deallocate_deserialized_V1_advertisement(np_ffi_DeserializedV1Advertisement adv);
+
+/**
+ * Gets the tag of a `DeserializedV0Advertisement` tagged-union.
+ */
+np_ffi_DeserializedV0AdvertisementKind np_ffi_DeserializedV0Advertisement_kind(np_ffi_DeserializedV0Advertisement result);
+
+/**
+ * Casts a `DeserializedV0Advertisement` to the `Legible` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_LegibleDeserializedV0Advertisement np_ffi_DeserializedV0Advertisement_into_LEGIBLE(np_ffi_DeserializedV0Advertisement adv);
+
+/**
+ * Gets the number of DEs in a legible deserialized advertisement.
+ * Suitable as an iteration bound for `V0Payload#get_de`.
+ */
+uint8_t np_ffi_LegibleDeserializedV0Advertisement_get_num_des(np_ffi_LegibleDeserializedV0Advertisement adv);
+
+/**
+ * Gets just the data-element payload of a `LegibleDeserializedV0Advertisement`.
+ */
+np_ffi_V0Payload np_ffi_LegibleDeserializedV0Advertisement_into_payload(np_ffi_LegibleDeserializedV0Advertisement adv);
+
+/**
+ * Gets just the identity information associated with a `LegibleDeserializedV0Advertisement`.
+ */
+np_ffi_DeserializedV0Identity np_ffi_LegibleDeserializedV0Advertisement_into_identity(np_ffi_LegibleDeserializedV0Advertisement adv);
+
+/**
+ * Deallocates any internal data of a `LegibleDeserializedV0Advertisement`
+ */
+np_ffi_DeallocateResult np_ffi_deallocate_legible_v0_advertisement(np_ffi_LegibleDeserializedV0Advertisement adv);
+
+/**
+ * Gets the tag of the `DeserializedV0Identity` tagged-union.
+ */
+np_ffi_DeserializedV0IdentityKind np_ffi_DeserializedV0Identity_kind(np_ffi_DeserializedV0Identity identity);
+
+/**
+ * Attempts to get the data-element with the given index in the passed v0 adv payload
+ */
+np_ffi_GetV0DEResult np_ffi_V0Payload_get_de(np_ffi_V0Payload payload, uint8_t index);
+
+/**
+ * Deallocates any internal data of a `V0Payload`
+ */
+np_ffi_DeallocateResult np_ffi_deallocate_v0_payload(np_ffi_V0Payload payload);
+
+/**
+ * Gets the tag of a `GetV0DEResult` tagged-union.
+ */
+np_ffi_GetV0DEResultKind np_ffi_GetV0DEResult_kind(np_ffi_GetV0DEResult result);
+
+/**
+ * Casts a `GetV0DEResult` to the `Success` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_V0DataElement np_ffi_GetV0DEResult_into_SUCCESS(np_ffi_GetV0DEResult result);
+
+/**
+ * Gets the tag of a `V0DataElement` tagged-union.
+ */
+np_ffi_V0DataElementKind np_ffi_V0DataElement_kind(np_ffi_V0DataElement de);
+
+/**
+ * Casts a `V0DataElement` to the `TxPower` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_TxPower np_ffi_V0DataElement_into_TX_POWER(np_ffi_V0DataElement de);
+
+/**
+ * Casts a `V0DataElement` to the `Actions` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_V0Actions np_ffi_V0DataElement_into_ACTIONS(np_ffi_V0DataElement de);
+
+/**
+ * Return whether a boolean action type is set in this data element
+ */
+bool np_ffi_V0Actions_has_action(np_ffi_V0Actions actions, np_ffi_BooleanActionType action_type);
+
+/**
+ * Gets the 4 bit context sync sequence number as a u8 from this data element
+ */
+uint8_t np_ffi_V0Actions_get_context_sync_sequence_number(np_ffi_V0Actions actions);
+
+/**
+ * Return whether a boolean action type is set in this data element
+ */
+uint32_t np_ffi_V0Actions_as_u32(np_ffi_V0Actions actions);
+
+/**
+ * Gets the number of legible sections on a deserialized V1 advertisement.
+ * Suitable as an index bound for the second argument of
+ * `np_ffi_DeserializedV1Advertisement#get_section`.
+ */
+uint8_t np_ffi_DeserializedV1Advertisement_get_num_legible_sections(np_ffi_DeserializedV1Advertisement adv);
+
+/**
+ * Gets the number of sections on a deserialized V1 advertisement which
+ * were unable to be decrypted with the credentials that the receiver possesses.
+ */
+uint8_t np_ffi_DeserializedV1Advertisement_get_num_undecryptable_sections(np_ffi_DeserializedV1Advertisement adv);
+
+/**
+ * Gets the legible section with the given index in a deserialized V1 advertisement.
+ */
+np_ffi_GetV1SectionResult np_ffi_DeserializedV1Advertisement_get_section(np_ffi_DeserializedV1Advertisement adv,
+                                                                         uint8_t legible_section_index);
+
+/**
+ * Gets the tag of the `GetV1SectionResult` tagged-union.
+ */
+np_ffi_GetV1SectionResultKind np_ffi_GetV1SectionResult_kind(np_ffi_GetV1SectionResult result);
+
+/**
+ * Casts a `GetV1SectionResult` to the `Success` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_DeserializedV1Section np_ffi_GetV1SectionResult_into_SUCCESS(np_ffi_GetV1SectionResult result);
+
+/**
+ * Gets the number of data elements in a deserialized v1 section.
+ * Suitable as an iteration bound for the second argument of
+ * `np_ffi_DeserializedV1Section_get_de`.
+ */
+uint8_t np_ffi_DeserializedV1Section_get_num_des(np_ffi_DeserializedV1Section section);
+
+/**
+ * Gets the tag of the identity tagged-union used for the passed section.
+ */
+np_ffi_DeserializedV1IdentityKind np_ffi_DeserializedV1Section_get_identity_kind(np_ffi_DeserializedV1Section section);
+
+/**
+ * Gets the data-element with the given index in the passed section.
+ */
+np_ffi_GetV1DEResult np_ffi_DeserializedV1Section_get_de(np_ffi_DeserializedV1Section section,
+                                                         uint8_t de_index);
+
+/**
+ * Gets the tag of the `GetV1DEResult` tagged-union.
+ */
+np_ffi_GetV1DEResultKind np_ffi_GetV1DEResult_kind(np_ffi_GetV1DEResult result);
+
+/**
+ * Casts a `GetV1DEResult` to the `Success` vartiant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_V1DataElement np_ffi_GetV1DEResult_into_SUCCESS(np_ffi_GetV1DEResult result);
+
+/**
+ * Converts a `V1DataElement` to a `GenericV1DataElement` which
+ * only maintains information about the DE's type-code and payload.
+ */
+np_ffi_GenericV1DataElement np_ffi_V1DataElement_to_generic(np_ffi_V1DataElement de);
+
+/**
+ * Extracts the numerical value of the given V1 DE type code as
+ * an unsigned 32-bit integer.
+ */
+uint32_t np_ffi_V1DEType_to_uint32_t(np_ffi_V1DEType de_type);
diff --git a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h
new file mode 100644
index 0000000..3361c5d
--- /dev/null
+++ b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h
@@ -0,0 +1,268 @@
+/*
+ Copyright 2023 Google LLC
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+
+#pragma once
+
+/* Generated with cbindgen:0.24.5 */
+
+/*
+ WARNING: this file is autogenerated by cbindgen. Don't modify this manually.
+ Additionally, you should _not_ rely upon the layouts of the generated
+ structs and unions if you want your code to be forward-compatible,
+ unless a given type explicitly states in its documentation that it has
+ a guaranteed forward-compatible layout.
+ Instead, you should use _only_ the provided exported function symbols.
+*/
+
+#include <cstdarg>
+#include <cstdint>
+#include <cstdlib>
+#include <ostream>
+#include <new>
+#include "np_cpp_ffi_types.h"
+
+namespace np_ffi {
+namespace internal {
+
+extern "C" {
+
+/// Overrides the global panic handler to be used when NP C FFI calls panic.
+/// This method will only have an effect on the global panic-handler
+/// the first time it's called, and this method will return `true`
+/// to indicate that the panic handler was successfully set.
+/// All subsequent calls to this method
+/// will simply ignore the argument and return `false`.
+///
+/// If the passed function pointer is non-null,
+/// then we will call it upon every panic,
+/// followed by the default panicking behavior for
+/// the platform (in the case where the user-specified
+/// function does not terminate or hang the running process.)
+///
+/// Otherwise, we will resort to the
+/// default panicking behavior for the system, which
+/// is a printed stack trace followed by an abort
+/// when this crate is compiled with `std`,
+/// but a bare `loop { }` when this crate is compiled without.
+bool np_ffi_global_config_panic_handler(void (*handler)(PanicReason));
+
+/// Sets an override to the number of shards to employ in the NP FFI's
+/// internal handle-maps, which places an upper bound on the number
+/// of writing threads which may make progress at any one time
+/// when concurrently accessing handles of the same type.
+///
+/// By default, this value will be set to 16, or in `std` environments,
+/// the minimum of 16 and the number of available hardware threads.
+/// A shard value override of zero will be interpreted the same
+/// as this default.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of _any_ non-`np_ffi_global_config_set`
+/// API call.
+void np_ffi_global_config_set_num_shards(uint8_t num_shards);
+
+/// Sets the maximum number of active handles to credential books
+/// which may be active at any one time.
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on credential books in constrained-memory environments.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call utilizing credential books.
+void np_ffi_global_config_set_max_num_credential_books(uint32_t max_num_credential_books);
+
+/// Sets the maximum number of active handles to deserialized v0
+/// advertisements which may be active at any one time.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on v0 advertisements in constrained-memory environments.
+///
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call which references or returns a deserialized V0 advertisement.
+void np_ffi_global_config_set_max_num_deserialized_v0_advertisements(uint32_t max_num_deserialized_v0_advertisements);
+
+/// Sets the maximum number of active handles to deserialized v1
+/// advertisements which may be active at any one time.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on v1 advertisements in constrained-memory environments.
+///
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call which references or returns a deserialized V1 advertisement.
+void np_ffi_global_config_set_max_num_deserialized_v1_advertisements(uint32_t max_num_deserialized_v1_advertisements);
+
+/// Allocates a new credential-book, returning a handle to the created object
+CreateCredentialBookResult np_ffi_create_credential_book();
+
+/// Gets the tag of a `CreateCredentialBookResult` tagged enum.
+CreateCredentialBookResultKind np_ffi_CreateCredentialBookResult_kind(CreateCredentialBookResult result);
+
+/// Casts a `CreateCredentialBookResult` to the `SUCCESS` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+CredentialBook np_ffi_CreateCredentialBookResult_into_SUCCESS(CreateCredentialBookResult result);
+
+/// Deallocates a credential-book by its handle
+DeallocateResult np_ffi_deallocate_credential_book(CredentialBook credential_book);
+
+/// Attempts to deserialize an advertisement with the given service-data
+/// payload (presumed to be under the NP service UUID) using credentials
+/// pulled from the given credential-book.
+DeserializeAdvertisementResult np_ffi_deserialize_advertisement(RawAdvertisementPayload adv_payload,
+                                                                CredentialBook credential_book);
+
+/// Gets the tag of a `DeserializeAdvertisementResult` tagged-union.
+DeserializeAdvertisementResultKind np_ffi_DeserializeAdvertisementResult_kind(DeserializeAdvertisementResult result);
+
+/// Casts a `DeserializeAdvertisementResult` to the `V0` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+DeserializedV0Advertisement np_ffi_DeserializeAdvertisementResult_into_V0(DeserializeAdvertisementResult result);
+
+/// Casts a `DeserializeAdvertisementResult` to the `V1` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+DeserializedV1Advertisement np_ffi_DeserializeAdvertisementResult_into_V1(DeserializeAdvertisementResult result);
+
+/// Deallocates any internal data referenced by a `DeserializeAdvertisementResult`. This should only
+/// be used if into_V0 or into_V1, have not been called yet as it shares the same underlying
+/// resource.
+DeallocateResult np_ffi_deallocate_deserialize_advertisement_result(DeserializeAdvertisementResult result);
+
+/// Deallocates any internal data referenced by a `DeserializedV0Advertisement`
+DeallocateResult np_ffi_deallocate_deserialized_V0_advertisement(DeserializedV0Advertisement adv);
+
+/// Deallocates any internal data referenced by a `DeserializedV1Advertisement`
+DeallocateResult np_ffi_deallocate_deserialized_V1_advertisement(DeserializedV1Advertisement adv);
+
+/// Gets the tag of a `DeserializedV0Advertisement` tagged-union.
+DeserializedV0AdvertisementKind np_ffi_DeserializedV0Advertisement_kind(DeserializedV0Advertisement result);
+
+/// Casts a `DeserializedV0Advertisement` to the `Legible` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+LegibleDeserializedV0Advertisement np_ffi_DeserializedV0Advertisement_into_LEGIBLE(DeserializedV0Advertisement adv);
+
+/// Gets the number of DEs in a legible deserialized advertisement.
+/// Suitable as an iteration bound for `V0Payload#get_de`.
+uint8_t np_ffi_LegibleDeserializedV0Advertisement_get_num_des(LegibleDeserializedV0Advertisement adv);
+
+/// Gets just the data-element payload of a `LegibleDeserializedV0Advertisement`.
+V0Payload np_ffi_LegibleDeserializedV0Advertisement_into_payload(LegibleDeserializedV0Advertisement adv);
+
+/// Gets just the identity information associated with a `LegibleDeserializedV0Advertisement`.
+DeserializedV0Identity np_ffi_LegibleDeserializedV0Advertisement_into_identity(LegibleDeserializedV0Advertisement adv);
+
+/// Deallocates any internal data of a `LegibleDeserializedV0Advertisement`
+DeallocateResult np_ffi_deallocate_legible_v0_advertisement(LegibleDeserializedV0Advertisement adv);
+
+/// Gets the tag of the `DeserializedV0Identity` tagged-union.
+DeserializedV0IdentityKind np_ffi_DeserializedV0Identity_kind(DeserializedV0Identity identity);
+
+/// Attempts to get the data-element with the given index in the passed v0 adv payload
+GetV0DEResult np_ffi_V0Payload_get_de(V0Payload payload, uint8_t index);
+
+/// Deallocates any internal data of a `V0Payload`
+DeallocateResult np_ffi_deallocate_v0_payload(V0Payload payload);
+
+/// Gets the tag of a `GetV0DEResult` tagged-union.
+GetV0DEResultKind np_ffi_GetV0DEResult_kind(GetV0DEResult result);
+
+/// Casts a `GetV0DEResult` to the `Success` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+V0DataElement np_ffi_GetV0DEResult_into_SUCCESS(GetV0DEResult result);
+
+/// Gets the tag of a `V0DataElement` tagged-union.
+V0DataElementKind np_ffi_V0DataElement_kind(V0DataElement de);
+
+/// Casts a `V0DataElement` to the `TxPower` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+TxPower np_ffi_V0DataElement_into_TX_POWER(V0DataElement de);
+
+/// Casts a `V0DataElement` to the `Actions` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+V0Actions np_ffi_V0DataElement_into_ACTIONS(V0DataElement de);
+
+/// Return whether a boolean action type is set in this data element
+bool np_ffi_V0Actions_has_action(V0Actions actions, BooleanActionType action_type);
+
+/// Gets the 4 bit context sync sequence number as a u8 from this data element
+uint8_t np_ffi_V0Actions_get_context_sync_sequence_number(V0Actions actions);
+
+/// Return whether a boolean action type is set in this data element
+uint32_t np_ffi_V0Actions_as_u32(V0Actions actions);
+
+/// Gets the number of legible sections on a deserialized V1 advertisement.
+/// Suitable as an index bound for the second argument of
+/// `np_ffi_DeserializedV1Advertisement#get_section`.
+uint8_t np_ffi_DeserializedV1Advertisement_get_num_legible_sections(DeserializedV1Advertisement adv);
+
+/// Gets the number of sections on a deserialized V1 advertisement which
+/// were unable to be decrypted with the credentials that the receiver possesses.
+uint8_t np_ffi_DeserializedV1Advertisement_get_num_undecryptable_sections(DeserializedV1Advertisement adv);
+
+/// Gets the legible section with the given index in a deserialized V1 advertisement.
+GetV1SectionResult np_ffi_DeserializedV1Advertisement_get_section(DeserializedV1Advertisement adv,
+                                                                  uint8_t legible_section_index);
+
+/// Gets the tag of the `GetV1SectionResult` tagged-union.
+GetV1SectionResultKind np_ffi_GetV1SectionResult_kind(GetV1SectionResult result);
+
+/// Casts a `GetV1SectionResult` to the `Success` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+DeserializedV1Section np_ffi_GetV1SectionResult_into_SUCCESS(GetV1SectionResult result);
+
+/// Gets the number of data elements in a deserialized v1 section.
+/// Suitable as an iteration bound for the second argument of
+/// `np_ffi_DeserializedV1Section_get_de`.
+uint8_t np_ffi_DeserializedV1Section_get_num_des(DeserializedV1Section section);
+
+/// Gets the tag of the identity tagged-union used for the passed section.
+DeserializedV1IdentityKind np_ffi_DeserializedV1Section_get_identity_kind(DeserializedV1Section section);
+
+/// Gets the data-element with the given index in the passed section.
+GetV1DEResult np_ffi_DeserializedV1Section_get_de(DeserializedV1Section section, uint8_t de_index);
+
+/// Gets the tag of the `GetV1DEResult` tagged-union.
+GetV1DEResultKind np_ffi_GetV1DEResult_kind(GetV1DEResult result);
+
+/// Casts a `GetV1DEResult` to the `Success` vartiant, panicking in the
+/// case where the passed value is of a different enum variant.
+V1DataElement np_ffi_GetV1DEResult_into_SUCCESS(GetV1DEResult result);
+
+/// Converts a `V1DataElement` to a `GenericV1DataElement` which
+/// only maintains information about the DE's type-code and payload.
+GenericV1DataElement np_ffi_V1DataElement_to_generic(V1DataElement de);
+
+/// Extracts the numerical value of the given V1 DE type code as
+/// an unsigned 32-bit integer.
+uint32_t np_ffi_V1DEType_to_uint32_t(V1DEType de_type);
+
+} // extern "C"
+
+} // namespace internal
+} // namespace np_ffi
diff --git a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h
new file mode 100644
index 0000000..4d66308
--- /dev/null
+++ b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h
@@ -0,0 +1,456 @@
+/*
+ Copyright 2023 Google LLC
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+
+#pragma once
+
+/* Generated with cbindgen:0.24.5 */
+
+/*
+ WARNING: this file is autogenerated by cbindgen. Don't modify this manually.
+ Additionally, you should _not_ rely upon the layouts of the generated
+ structs and unions if you want your code to be forward-compatible,
+ unless a given type explicitly states in its documentation that it has
+ a guaranteed forward-compatible layout.
+ Instead, you should use _only_ the provided exported function symbols.
+*/
+
+#include <cstdarg>
+#include <cstdint>
+#include <cstdlib>
+#include <ostream>
+#include <new>
+
+namespace np_ffi {
+namespace internal {
+
+/// The possible boolean action types which can be present in an Actions data element
+enum class BooleanActionType : uint8_t {
+  ActiveUnlock = 8,
+  NearbyShare = 9,
+  InstantTethering = 10,
+  PhoneHub = 11,
+  PresenceManager = 12,
+  Finder = 13,
+  FastPairSass = 14,
+};
+
+/// Discriminant for `CreateCredentialBookResult`
+enum class CreateCredentialBookResultKind : uint8_t {
+  /// There was no space left to create a new credential book
+  NoSpaceLeft = 0,
+  /// We created a new credential book behind the given handle.
+  /// The associated payload may be obtained via
+  /// `CreateCredentialBookResult#into_success()`.
+  Success = 1,
+};
+
+/// A result-type enum which tells the caller whether/not a deallocation
+/// succeeded or failed due to the requested handle not being present.
+enum class DeallocateResult {
+  /// The requested handle to deallocate was not present in the map
+  NotPresent = 0,
+  /// The object behind the handle was successfully deallocated
+  Success = 1,
+};
+
+/// Discriminant for `DeserializeAdvertisementResult`.
+enum class DeserializeAdvertisementResultKind : uint8_t {
+  /// Deserializing the advertisement failed, for some reason or another.
+  Error = 0,
+  /// The advertisement was correctly deserialized, and it's a V0 advertisement.
+  /// `DeserializeAdvertisementResult#into_v0()` is the corresponding cast
+  /// to the associated enum variant.
+  V0 = 1,
+  /// The advertisement was correctly deserialized, and it's a V1 advertisement.
+  /// `DeserializeAdvertisementResult#into_v1()` is the corresponding cast
+  /// to the associated enum variant.
+  V1 = 2,
+};
+
+/// Discriminant for possible results of V0 advertisement deserialization
+enum class DeserializedV0AdvertisementKind : uint8_t {
+  /// The deserialized V0 advertisement was legible.
+  /// The associated payload may be obtained via
+  /// `DeserializedV0Advertisement#into_legible`.
+  Legible = 0,
+  /// The deserialized V0 advertisement is illegible,
+  /// likely meaning that the receiver does not hold
+  /// the proper credentials to be able to read
+  /// the received advertisement.
+  NoMatchingCredentials = 1,
+};
+
+/// Represents deserialized information about the V0 identity utilized
+/// by a deserialized V0 advertisement
+enum class DeserializedV0Identity {
+  Plaintext,
+  Decrypted,
+};
+
+/// Discriminant for `DeserializedV0Identity`.
+enum class DeserializedV0IdentityKind : uint8_t {
+  /// The deserialized identity was a plaintext identity.
+  Plaintext = 0,
+  /// The deserialized identity was some decrypted identity.
+  Decrypted = 1,
+};
+
+/// Discriminant for `DeserializedV1Identity`.
+enum class DeserializedV1IdentityKind : uint8_t {
+  /// The deserialized v1 identity was plaintext
+  Plaintext = 0,
+  /// The deserialized v1 identity corresponded
+  /// to some kind of decrypted identity.
+  Decrypted = 1,
+};
+
+/// Discriminant of `GetV0DEResult`.
+enum class GetV0DEResultKind : uint8_t {
+  /// The attempt to get the DE succeeded.
+  /// The associated payload may be obtained via
+  /// `GetV0DEResult#into_success`.
+  Success = 0,
+  /// The attempt to get the DE failed,
+  /// possibly due to the requested index being
+  /// out-of-bounds or due to the advertisement
+  /// having been previously deallocated.
+  Error = 1,
+};
+
+/// Discriminant for the `GetV1DEResult` enum.
+enum class GetV1DEResultKind : uint8_t {
+  /// Attempting to get the DE at the given position failed,
+  /// possibly due to the index being out-of-bounds or due
+  /// to the whole advertisement having been previously deallocated.
+  Error = 0,
+  /// Attempting to get the DE at the given position succeeded.
+  /// The underlying DE may be extracted with `GetV1DEResult#into_success`.
+  Success = 1,
+};
+
+/// Discriminant for `GetV1SectionResult`
+enum class GetV1SectionResultKind : uint8_t {
+  /// The attempt to get the section failed,
+  /// possibly due to the section index being
+  /// out-of-bounds or due to the underlying
+  /// advertisement having already been deallocated.
+  Error = 0,
+  /// The attempt to get the section succeeded.
+  /// The wrapped section may be obtained via
+  /// `GetV1SectionResult#into_success`.
+  Success = 1,
+};
+
+/// Structure for categorized reasons for why a NP C FFI call may
+/// be panicking.
+enum class PanicReason : uint8_t {
+  /// Some enum cast to a variant failed. Utilized
+  /// for failed enum casts of all enums.
+  ///
+  /// (That is, this is the catch-all panic reason for enum
+  /// casts where there is not a more specific reason
+  /// in some other variant of this enum.)
+  EnumCastFailed = 0,
+  /// The panic handler is used to assert conditions are true to avoid programmer errors.
+  /// If a failed assert condition is hit, this panic handler is invoked with this reason.
+  AssertFailed = 1,
+  /// Error returned if action bits inside of a V0Actions struct are invalid. If the struct was
+  /// created by this deserializer, the bits will always be valid, they are only invalid if
+  /// a user reaches in and changes them to something invalid.
+  InvalidActionBits = 2,
+};
+
+/// Discriminant for `V0DataElement`.
+enum class V0DataElementKind : uint8_t {
+  /// A transmission Power (Tx Power) data-element.
+  /// The associated payload may be obtained via
+  /// `V0DataElement#into_tx_power`.
+  TxPower = 0,
+  /// The Actions data-element.
+  /// The associated payload may be obtained via
+  /// `V0DataElement#into_actions`.
+  Actions = 1,
+};
+
+///A `#[repr(C)]` handle to a value of type `super::CredentialBookInternals`.
+struct CredentialBook {
+  uint64_t handle_id;
+};
+
+/// Result type for `create_credential_book`
+union CreateCredentialBookResult {
+  enum class Tag : uint8_t {
+    NoSpaceLeft = 0,
+    Success = 1,
+  };
+
+  struct Success_Body {
+    Tag tag;
+    CredentialBook _0;
+  };
+
+  struct {
+    Tag tag;
+  };
+  Success_Body success;
+};
+
+///A `#[repr(C)]` handle to a value of type `super::V0PayloadInternals`.
+struct V0Payload {
+  uint64_t handle_id;
+};
+
+/// Represents a deserialized V0 advertisement whose DE contents may be read
+struct LegibleDeserializedV0Advertisement {
+  uint8_t num_des;
+  V0Payload payload;
+  DeserializedV0Identity identity;
+};
+
+/// Represents a deserialized V0 advertisement
+struct DeserializedV0Advertisement {
+  enum class Tag {
+    Legible,
+    NoMatchingCredentials,
+  };
+
+  struct Legible_Body {
+    LegibleDeserializedV0Advertisement _0;
+  };
+
+  Tag tag;
+  union {
+    Legible_Body legible;
+  };
+};
+
+///A `#[repr(C)]` handle to a value of type `super::LegibleV1SectionsInternals`.
+struct LegibleV1Sections {
+  uint64_t handle_id;
+};
+
+/// Representation of a deserialized V1 advertisement
+struct DeserializedV1Advertisement {
+  uint8_t num_legible_sections;
+  uint8_t num_undecryptable_sections;
+  LegibleV1Sections legible_sections;
+};
+
+/// The result of calling `np_ffi_deserialize_advertisement`.
+/// Must be explicitly deallocated after use with
+/// a corresponding `np_ffi_deallocate_deserialize_advertisement_result`
+union DeserializeAdvertisementResult {
+  enum class Tag : uint8_t {
+    /// Deserializing the advertisement failed, for some reason or another.
+    /// `DeserializeAdvertisementResultKind::Error` is the associated enum tag.
+    Error,
+    /// The advertisement was correctly deserialized, and it's a V0 advertisement.
+    /// `DeserializeAdvertisementResultKind::V0` is the associated enum tag.
+    V0,
+    /// The advertisement was correctly deserialized, and it's a V1 advertisement.
+    /// `DeserializeAdvertisementResultKind::V1` is the associated enum tag.
+    V1,
+  };
+
+  struct V0_Body {
+    Tag tag;
+    DeserializedV0Advertisement _0;
+  };
+
+  struct V1_Body {
+    Tag tag;
+    DeserializedV1Advertisement _0;
+  };
+
+  struct {
+    Tag tag;
+  };
+  V0_Body v0;
+  V1_Body v1;
+};
+
+/// A byte-string with a maximum size of N,
+/// where only the first `len` bytes are considered
+/// to contain the actual payload. N is only
+/// permitted to be between 0 and 255.
+template<uintptr_t N>
+struct ByteBuffer {
+  uint8_t len;
+  uint8_t bytes[N];
+};
+
+/// Represents the raw contents of the service payload data
+/// under the Nearby Presence service UUID
+struct RawAdvertisementPayload {
+  ByteBuffer<255> bytes;
+};
+
+/// Representation of a transmission power,
+/// as used for the Tx Power DE in V0 and V1.
+struct TxPower {
+  int8_t tx_power;
+};
+
+/// The bitfield data of a VOActions data element
+struct V0ActionBits {
+  uint32_t bitfield;
+};
+
+/// Representation of the Actions DE in V0.
+struct V0Actions {
+  enum class Tag {
+    /// A set of action bits which were present in a plaintext identity advertisement
+    Plaintext,
+    /// A set of action bits which were present in a encrypted identity advertisement
+    Encrypted,
+  };
+
+  struct Plaintext_Body {
+    V0ActionBits _0;
+  };
+
+  struct Encrypted_Body {
+    V0ActionBits _0;
+  };
+
+  Tag tag;
+  union {
+    Plaintext_Body plaintext;
+    Encrypted_Body encrypted;
+  };
+};
+
+/// Representation of a V0 data element.
+struct V0DataElement {
+  enum class Tag {
+    TxPower,
+    Actions,
+  };
+
+  struct TxPower_Body {
+    TxPower _0;
+  };
+
+  struct Actions_Body {
+    V0Actions _0;
+  };
+
+  Tag tag;
+  union {
+    TxPower_Body tx_power;
+    Actions_Body actions;
+  };
+};
+
+/// The result of `V0Payload#get_de`.
+struct GetV0DEResult {
+  enum class Tag {
+    Success,
+    Error,
+  };
+
+  struct Success_Body {
+    V0DataElement _0;
+  };
+
+  Tag tag;
+  union {
+    Success_Body success;
+  };
+};
+
+/// Handle to a deserialized V1 section
+struct DeserializedV1Section {
+  LegibleV1Sections legible_sections_handle;
+  uint8_t legible_section_index;
+  uint8_t num_des;
+  DeserializedV1IdentityKind identity_tag;
+};
+
+/// The result of attempting to get a particular V1 section
+/// from its' index within the list of legible sections
+/// via `DeserializedV1Advertisement::get_section`.
+struct GetV1SectionResult {
+  enum class Tag {
+    Error,
+    Success,
+  };
+
+  struct Success_Body {
+    DeserializedV1Section _0;
+  };
+
+  Tag tag;
+  union {
+    Success_Body success;
+  };
+};
+
+/// Representation of the data-element type tag
+/// of a V1 data element.
+struct V1DEType {
+  uint32_t code;
+};
+
+/// FFI-transmissible representation of a generic V1 data-element.
+/// This representation is stable, and so you may directly
+/// reference this struct's fields if you wish.
+struct GenericV1DataElement {
+  /// The DE type code of this generic data-element.
+  V1DEType de_type;
+  /// The raw data-element byte payload, up to
+  /// 127 bytes in length.
+  ByteBuffer<127> payload;
+};
+
+/// FFI-transmissible representation of a V1 data-element
+struct V1DataElement {
+  enum class Tag {
+    /// A "generic" V1 data-element, for which we have no
+    /// particular information about its schema (just
+    /// a DE type code and a byte payload.)
+    Generic,
+  };
+
+  struct Generic_Body {
+    GenericV1DataElement _0;
+  };
+
+  Tag tag;
+  union {
+    Generic_Body generic;
+  };
+};
+
+/// Represents the result of the `DeserializedV1Section#get_de` operation.
+struct GetV1DEResult {
+  enum class Tag {
+    Error,
+    Success,
+  };
+
+  struct Success_Body {
+    V1DataElement _0;
+  };
+
+  Tag tag;
+  union {
+    Success_Body success;
+  };
+};
+
+} // namespace internal
+} // namespace np_ffi
diff --git a/nearby/presence/np_c_ffi/rust-toolchain.toml b/nearby/presence/np_c_ffi/rust-toolchain.toml
new file mode 100644
index 0000000..271800c
--- /dev/null
+++ b/nearby/presence/np_c_ffi/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+channel = "nightly"
\ No newline at end of file
diff --git a/nearby/presence/np_c_ffi/src/credentials.rs b/nearby/presence/np_c_ffi/src/credentials.rs
new file mode 100644
index 0000000..6b60545
--- /dev/null
+++ b/nearby/presence/np_c_ffi/src/credentials.rs
@@ -0,0 +1,51 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//! Credential-related data-types and functions
+
+use crate::{unwrap, PanicReason};
+use np_ffi_core::common::*;
+use np_ffi_core::credentials::credential_book::CredentialBook;
+use np_ffi_core::credentials::*;
+use np_ffi_core::utils::FfiEnum;
+
+/// Allocates a new credential-book, returning a handle to the created object
+#[no_mangle]
+pub extern "C" fn np_ffi_create_credential_book() -> CreateCredentialBookResult {
+    create_credential_book()
+}
+
+/// Gets the tag of a `CreateCredentialBookResult` tagged enum.
+#[no_mangle]
+pub extern "C" fn np_ffi_CreateCredentialBookResult_kind(
+    result: CreateCredentialBookResult,
+) -> CreateCredentialBookResultKind {
+    result.kind()
+}
+
+/// Casts a `CreateCredentialBookResult` to the `SUCCESS` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_CreateCredentialBookResult_into_SUCCESS(
+    result: CreateCredentialBookResult,
+) -> CredentialBook {
+    unwrap(result.into_success(), PanicReason::EnumCastFailed)
+}
+
+/// Deallocates a credential-book by its handle
+#[no_mangle]
+pub extern "C" fn np_ffi_deallocate_credential_book(
+    credential_book: CredentialBook,
+) -> DeallocateResult {
+    deallocate_credential_book(credential_book)
+}
diff --git a/nearby/presence/np_c_ffi/src/deserialize/mod.rs b/nearby/presence/np_c_ffi/src/deserialize/mod.rs
new file mode 100644
index 0000000..9f2cea8
--- /dev/null
+++ b/nearby/presence/np_c_ffi/src/deserialize/mod.rs
@@ -0,0 +1,87 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::{unwrap, PanicReason};
+use np_ffi_core::common::*;
+use np_ffi_core::credentials::credential_book::CredentialBook;
+use np_ffi_core::deserialize::v0::*;
+use np_ffi_core::deserialize::v1::*;
+use np_ffi_core::deserialize::*;
+use np_ffi_core::utils::FfiEnum;
+
+mod v0;
+mod v1;
+
+/// Attempts to deserialize an advertisement with the given service-data
+/// payload (presumed to be under the NP service UUID) using credentials
+/// pulled from the given credential-book.
+#[no_mangle]
+pub extern "C" fn np_ffi_deserialize_advertisement(
+    adv_payload: RawAdvertisementPayload,
+    credential_book: CredentialBook,
+) -> DeserializeAdvertisementResult {
+    deserialize_advertisement(&adv_payload, credential_book)
+}
+
+/// Gets the tag of a `DeserializeAdvertisementResult` tagged-union.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializeAdvertisementResult_kind(
+    result: DeserializeAdvertisementResult,
+) -> DeserializeAdvertisementResultKind {
+    result.kind()
+}
+
+/// Casts a `DeserializeAdvertisementResult` to the `V0` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializeAdvertisementResult_into_V0(
+    result: DeserializeAdvertisementResult,
+) -> DeserializedV0Advertisement {
+    unwrap(result.into_v0(), PanicReason::EnumCastFailed)
+}
+
+/// Casts a `DeserializeAdvertisementResult` to the `V1` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializeAdvertisementResult_into_V1(
+    result: DeserializeAdvertisementResult,
+) -> DeserializedV1Advertisement {
+    unwrap(result.into_v1(), PanicReason::EnumCastFailed)
+}
+
+/// Deallocates any internal data referenced by a `DeserializeAdvertisementResult`. This should only
+/// be used if into_V0 or into_V1, have not been called yet as it shares the same underlying
+/// resource.
+#[no_mangle]
+pub extern "C" fn np_ffi_deallocate_deserialize_advertisement_result(
+    result: DeserializeAdvertisementResult,
+) -> DeallocateResult {
+    result.deallocate()
+}
+
+/// Deallocates any internal data referenced by a `DeserializedV0Advertisement`
+#[no_mangle]
+pub extern "C" fn np_ffi_deallocate_deserialized_V0_advertisement(
+    adv: DeserializedV0Advertisement,
+) -> DeallocateResult {
+    adv.deallocate()
+}
+
+/// Deallocates any internal data referenced by a `DeserializedV1Advertisement`
+#[no_mangle]
+pub extern "C" fn np_ffi_deallocate_deserialized_V1_advertisement(
+    adv: DeserializedV1Advertisement,
+) -> DeallocateResult {
+    adv.deallocate()
+}
diff --git a/nearby/presence/np_c_ffi/src/deserialize/v0.rs b/nearby/presence/np_c_ffi/src/deserialize/v0.rs
new file mode 100644
index 0000000..877cee5
--- /dev/null
+++ b/nearby/presence/np_c_ffi/src/deserialize/v0.rs
@@ -0,0 +1,149 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::{panic, unwrap, PanicReason};
+use np_ffi_core::common::DeallocateResult;
+use np_ffi_core::deserialize::v0::v0_payload::V0Payload;
+use np_ffi_core::deserialize::v0::*;
+use np_ffi_core::utils::FfiEnum;
+
+/// Gets the tag of a `DeserializedV0Advertisement` tagged-union.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV0Advertisement_kind(
+    result: DeserializedV0Advertisement,
+) -> DeserializedV0AdvertisementKind {
+    result.kind()
+}
+
+/// Casts a `DeserializedV0Advertisement` to the `Legible` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV0Advertisement_into_LEGIBLE(
+    adv: DeserializedV0Advertisement,
+) -> LegibleDeserializedV0Advertisement {
+    unwrap(adv.into_legible(), PanicReason::EnumCastFailed)
+}
+
+/// Gets the number of DEs in a legible deserialized advertisement.
+/// Suitable as an iteration bound for `V0Payload#get_de`.
+#[no_mangle]
+pub extern "C" fn np_ffi_LegibleDeserializedV0Advertisement_get_num_des(
+    adv: LegibleDeserializedV0Advertisement,
+) -> u8 {
+    adv.num_des()
+}
+
+/// Gets just the data-element payload of a `LegibleDeserializedV0Advertisement`.
+#[no_mangle]
+pub extern "C" fn np_ffi_LegibleDeserializedV0Advertisement_into_payload(
+    adv: LegibleDeserializedV0Advertisement,
+) -> V0Payload {
+    adv.into_payload()
+}
+
+/// Gets just the identity information associated with a `LegibleDeserializedV0Advertisement`.
+#[no_mangle]
+pub extern "C" fn np_ffi_LegibleDeserializedV0Advertisement_into_identity(
+    adv: LegibleDeserializedV0Advertisement,
+) -> DeserializedV0Identity {
+    adv.into_identity()
+}
+
+/// Deallocates any internal data of a `LegibleDeserializedV0Advertisement`
+#[no_mangle]
+pub extern "C" fn np_ffi_deallocate_legible_v0_advertisement(
+    adv: LegibleDeserializedV0Advertisement,
+) -> DeallocateResult {
+    adv.deallocate()
+}
+
+/// Gets the tag of the `DeserializedV0Identity` tagged-union.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV0Identity_kind(
+    identity: DeserializedV0Identity,
+) -> DeserializedV0IdentityKind {
+    identity.kind()
+}
+
+/// Attempts to get the data-element with the given index in the passed v0 adv payload
+#[no_mangle]
+pub extern "C" fn np_ffi_V0Payload_get_de(payload: V0Payload, index: u8) -> GetV0DEResult {
+    payload.get_de(index)
+}
+
+/// Deallocates any internal data of a `V0Payload`
+#[no_mangle]
+pub extern "C" fn np_ffi_deallocate_v0_payload(payload: V0Payload) -> DeallocateResult {
+    payload.deallocate_payload()
+}
+
+/// Gets the tag of a `GetV0DEResult` tagged-union.
+#[no_mangle]
+pub extern "C" fn np_ffi_GetV0DEResult_kind(result: GetV0DEResult) -> GetV0DEResultKind {
+    result.kind()
+}
+
+/// Casts a `GetV0DEResult` to the `Success` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_GetV0DEResult_into_SUCCESS(result: GetV0DEResult) -> V0DataElement {
+    unwrap(result.into_success(), PanicReason::EnumCastFailed)
+}
+
+/// Gets the tag of a `V0DataElement` tagged-union.
+#[no_mangle]
+pub extern "C" fn np_ffi_V0DataElement_kind(de: V0DataElement) -> V0DataElementKind {
+    de.kind()
+}
+
+/// Casts a `V0DataElement` to the `TxPower` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_V0DataElement_into_TX_POWER(de: V0DataElement) -> TxPower {
+    unwrap(de.into_tx_power(), PanicReason::EnumCastFailed)
+}
+
+/// Casts a `V0DataElement` to the `Actions` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_V0DataElement_into_ACTIONS(de: V0DataElement) -> V0Actions {
+    unwrap(de.into_actions(), PanicReason::EnumCastFailed)
+}
+
+/// Return whether a boolean action type is set in this data element
+#[no_mangle]
+pub extern "C" fn np_ffi_V0Actions_has_action(
+    actions: V0Actions,
+    action_type: BooleanActionType,
+) -> bool {
+    match actions.has_action(&action_type) {
+        Ok(b) => b,
+        Err(_) => panic(PanicReason::InvalidActionBits),
+    }
+}
+
+/// Gets the 4 bit context sync sequence number as a u8 from this data element
+#[no_mangle]
+pub extern "C" fn np_ffi_V0Actions_get_context_sync_sequence_number(actions: V0Actions) -> u8 {
+    match actions.get_context_sync_seq_num() {
+        Ok(b) => b,
+        Err(_) => panic(PanicReason::InvalidActionBits),
+    }
+}
+
+/// Return whether a boolean action type is set in this data element
+#[no_mangle]
+pub extern "C" fn np_ffi_V0Actions_as_u32(actions: V0Actions) -> u32 {
+    actions.as_u32()
+}
diff --git a/nearby/presence/np_c_ffi/src/deserialize/v1.rs b/nearby/presence/np_c_ffi/src/deserialize/v1.rs
new file mode 100644
index 0000000..dc682a3
--- /dev/null
+++ b/nearby/presence/np_c_ffi/src/deserialize/v1.rs
@@ -0,0 +1,114 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::{unwrap, PanicReason};
+use np_ffi_core::deserialize::v1::*;
+use np_ffi_core::utils::FfiEnum;
+
+/// Gets the number of legible sections on a deserialized V1 advertisement.
+/// Suitable as an index bound for the second argument of
+/// `np_ffi_DeserializedV1Advertisement#get_section`.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV1Advertisement_get_num_legible_sections(
+    adv: DeserializedV1Advertisement,
+) -> u8 {
+    adv.num_legible_sections()
+}
+
+/// Gets the number of sections on a deserialized V1 advertisement which
+/// were unable to be decrypted with the credentials that the receiver possesses.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV1Advertisement_get_num_undecryptable_sections(
+    adv: DeserializedV1Advertisement,
+) -> u8 {
+    adv.num_undecryptable_sections()
+}
+
+/// Gets the legible section with the given index in a deserialized V1 advertisement.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV1Advertisement_get_section(
+    adv: DeserializedV1Advertisement,
+    legible_section_index: u8,
+) -> GetV1SectionResult {
+    adv.get_section(legible_section_index)
+}
+
+/// Gets the tag of the `GetV1SectionResult` tagged-union.
+#[no_mangle]
+pub extern "C" fn np_ffi_GetV1SectionResult_kind(
+    result: GetV1SectionResult,
+) -> GetV1SectionResultKind {
+    result.kind()
+}
+
+/// Casts a `GetV1SectionResult` to the `Success` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_GetV1SectionResult_into_SUCCESS(
+    result: GetV1SectionResult,
+) -> DeserializedV1Section {
+    unwrap(result.into_success(), PanicReason::EnumCastFailed)
+}
+
+/// Gets the number of data elements in a deserialized v1 section.
+/// Suitable as an iteration bound for the second argument of
+/// `np_ffi_DeserializedV1Section_get_de`.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV1Section_get_num_des(section: DeserializedV1Section) -> u8 {
+    section.num_des()
+}
+
+/// Gets the tag of the identity tagged-union used for the passed section.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV1Section_get_identity_kind(
+    section: DeserializedV1Section,
+) -> DeserializedV1IdentityKind {
+    section.identity_kind()
+}
+
+/// Gets the data-element with the given index in the passed section.
+#[no_mangle]
+pub extern "C" fn np_ffi_DeserializedV1Section_get_de(
+    section: DeserializedV1Section,
+    de_index: u8,
+) -> GetV1DEResult {
+    section.get_de(de_index)
+}
+
+/// Gets the tag of the `GetV1DEResult` tagged-union.
+#[no_mangle]
+pub extern "C" fn np_ffi_GetV1DEResult_kind(result: GetV1DEResult) -> GetV1DEResultKind {
+    result.kind()
+}
+
+/// Casts a `GetV1DEResult` to the `Success` vartiant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_GetV1DEResult_into_SUCCESS(result: GetV1DEResult) -> V1DataElement {
+    unwrap(result.into_success(), PanicReason::EnumCastFailed)
+}
+
+/// Converts a `V1DataElement` to a `GenericV1DataElement` which
+/// only maintains information about the DE's type-code and payload.
+#[no_mangle]
+pub extern "C" fn np_ffi_V1DataElement_to_generic(de: V1DataElement) -> GenericV1DataElement {
+    de.to_generic()
+}
+
+/// Extracts the numerical value of the given V1 DE type code as
+/// an unsigned 32-bit integer.
+#[no_mangle]
+pub extern "C" fn np_ffi_V1DEType_to_uint32_t(de_type: V1DEType) -> u32 {
+    de_type.to_u32()
+}
diff --git a/nearby/presence/np_c_ffi/src/lib.rs b/nearby/presence/np_c_ffi/src/lib.rs
new file mode 100644
index 0000000..bd475ab
--- /dev/null
+++ b/nearby/presence/np_c_ffi/src/lib.rs
@@ -0,0 +1,221 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! NP Rust C FFI
+
+#![cfg_attr(not(test), no_std)]
+#![allow(dead_code)]
+extern crate alloc;
+extern crate core;
+
+pub mod credentials;
+pub mod deserialize;
+
+/// Structure for categorized reasons for why a NP C FFI call may
+/// be panicking.
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum PanicReason {
+    /// Some enum cast to a variant failed. Utilized
+    /// for failed enum casts of all enums.
+    ///
+    /// (That is, this is the catch-all panic reason for enum
+    /// casts where there is not a more specific reason
+    /// in some other variant of this enum.)
+    EnumCastFailed = 0,
+    /// The panic handler is used to assert conditions are true to avoid programmer errors.
+    /// If a failed assert condition is hit, this panic handler is invoked with this reason.
+    AssertFailed = 1,
+    /// Error returned if action bits inside of a V0Actions struct are invalid. If the struct was
+    /// created by this deserializer, the bits will always be valid, they are only invalid if
+    /// a user reaches in and changes them to something invalid.
+    InvalidActionBits = 2,
+}
+
+/// Structure which maintains information about the panic-handler
+/// for panicking calls in the NP C FFI.
+#[derive(Debug)]
+struct PanicHandler {
+    /// Optional function-pointer to client-specified panic behavior.
+    handler: Option<unsafe extern "C" fn(PanicReason) -> ()>,
+
+    /// Fuse to prevent setting the panic-handler more than once.
+    /// We do not use the presence/absence of `self.handler` for this,
+    /// since it's possible for the client to explicitly pass "NULL"
+    /// to set the panic-handler to the platform-default (and ensure
+    /// that the panic-handler never changes from the platform-default.)
+    handler_set_by_client: bool,
+}
+
+impl PanicHandler {
+    pub(crate) const fn new() -> Self {
+        Self { handler: None, handler_set_by_client: false }
+    }
+    pub(crate) fn set_handler(
+        &mut self,
+        handler: Option<unsafe extern "C" fn(PanicReason) -> ()>,
+    ) -> bool {
+        // Only allow setting the panic handler once
+        if !self.handler_set_by_client {
+            self.handler = handler;
+            self.handler_set_by_client = true;
+            true
+        } else {
+            false
+        }
+    }
+    pub(crate) fn panic(&self, panic_reason: PanicReason) -> ! {
+        if let Some(handler) = self.handler {
+            unsafe { handler(panic_reason) }
+        }
+        Self::system_handler(panic_reason)
+    }
+    #[cfg(feature = "std")]
+    fn system_handler(panic_reason: PanicReason) -> ! {
+        eprintln!("NP FFI Panicked: {:?}", panic_reason);
+        let backtrace = std::backtrace::Backtrace::capture();
+        eprintln!("Stack trace: {}", backtrace);
+        std::process::abort!();
+    }
+    #[cfg(not(feature = "std"))]
+    #[allow(clippy::empty_loop)]
+    fn system_handler(_: PanicReason) -> ! {
+        // Looping is the only platform-independent thing
+        // that we can really do in this scenario.
+        // (Even clippy's explanation for the empty-loop
+        // lint mentions platform-specific intrinsics
+        // as being the only true way to avoid this
+        // in a no_std environment.)
+        loop {}
+    }
+}
+
+static PANIC_HANDLER: spin::RwLock<PanicHandler> = spin::RwLock::new(PanicHandler::new());
+
+pub(crate) fn panic(reason: PanicReason) -> ! {
+    PANIC_HANDLER.read().panic(reason)
+}
+
+pub(crate) fn unwrap<T>(value: Option<T>, panic_reason: PanicReason) -> T {
+    match value {
+        Some(x) => x,
+        None => panic(panic_reason),
+    }
+}
+
+/// Overrides the global panic handler to be used when NP C FFI calls panic.
+/// This method will only have an effect on the global panic-handler
+/// the first time it's called, and this method will return `true`
+/// to indicate that the panic handler was successfully set.
+/// All subsequent calls to this method
+/// will simply ignore the argument and return `false`.
+///
+/// If the passed function pointer is non-null,
+/// then we will call it upon every panic,
+/// followed by the default panicking behavior for
+/// the platform (in the case where the user-specified
+/// function does not terminate or hang the running process.)
+///
+/// Otherwise, we will resort to the
+/// default panicking behavior for the system, which
+/// is a printed stack trace followed by an abort
+/// when this crate is compiled with `std`,
+/// but a bare `loop { }` when this crate is compiled without.
+#[no_mangle]
+pub extern "C" fn np_ffi_global_config_panic_handler(
+    handler: Option<unsafe extern "C" fn(PanicReason) -> ()>,
+) -> bool {
+    let mut panic_handler = PANIC_HANDLER.write();
+    panic_handler.set_handler(handler)
+}
+
+/// Sets an override to the number of shards to employ in the NP FFI's
+/// internal handle-maps, which places an upper bound on the number
+/// of writing threads which may make progress at any one time
+/// when concurrently accessing handles of the same type.
+///
+/// By default, this value will be set to 16, or in `std` environments,
+/// the minimum of 16 and the number of available hardware threads.
+/// A shard value override of zero will be interpreted the same
+/// as this default.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of _any_ non-`np_ffi_global_config_set`
+/// API call.
+#[no_mangle]
+pub extern "C" fn np_ffi_global_config_set_num_shards(num_shards: u8) {
+    np_ffi_core::common::global_config_set_num_shards(num_shards)
+}
+
+/// Sets the maximum number of active handles to credential books
+/// which may be active at any one time.
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on credential books in constrained-memory environments.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call utilizing credential books.
+#[no_mangle]
+pub extern "C" fn np_ffi_global_config_set_max_num_credential_books(max_num_credential_books: u32) {
+    np_ffi_core::common::global_config_set_max_num_credential_books(max_num_credential_books)
+}
+
+/// Sets the maximum number of active handles to deserialized v0
+/// advertisements which may be active at any one time.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on v0 advertisements in constrained-memory environments.
+///
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call which references or returns a deserialized V0 advertisement.
+#[no_mangle]
+pub extern "C" fn np_ffi_global_config_set_max_num_deserialized_v0_advertisements(
+    max_num_deserialized_v0_advertisements: u32,
+) {
+    np_ffi_core::common::global_config_set_max_num_deserialized_v0_advertisements(
+        max_num_deserialized_v0_advertisements,
+    )
+}
+
+/// Sets the maximum number of active handles to deserialized v1
+/// advertisements which may be active at any one time.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on v1 advertisements in constrained-memory environments.
+///
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call which references or returns a deserialized V1 advertisement.
+#[no_mangle]
+pub extern "C" fn np_ffi_global_config_set_max_num_deserialized_v1_advertisements(
+    max_num_deserialized_v1_advertisements: u32,
+) {
+    np_ffi_core::common::global_config_set_max_num_deserialized_v1_advertisements(
+        max_num_deserialized_v1_advertisements,
+    )
+}