Project import generated by Copybara.

GitOrigin-RevId: b6ca065e6fc9504c3ff07067ef2da184afaf0c78
Change-Id: Ie3b3a5835bf622e679fd21e0a9149dd85da59aca
diff --git a/nearby/Cargo.lock b/nearby/Cargo.lock
index 7dc0e09..4730df4 100644
--- a/nearby/Cargo.lock
+++ b/nearby/Cargo.lock
@@ -501,7 +501,6 @@
  "rand 0.8.5",
  "rand_chacha 0.3.1",
  "rand_core 0.6.4",
- "rand_core_05_adapter",
  "sec1",
  "sha2 0.10.6",
  "subtle",
@@ -594,6 +593,7 @@
  "curve25519-dalek",
  "ed25519",
  "rand 0.7.3",
+ "rand_core 0.5.1",
  "serde",
  "sha2 0.9.9",
  "zeroize",
@@ -1054,7 +1054,9 @@
  "anyhow",
  "array_view",
  "base64 0.21.0",
+ "criterion",
  "crypto_provider",
+ "crypto_provider_openssl",
  "crypto_provider_rustcrypto",
  "hex",
  "ldt",
@@ -1062,6 +1064,7 @@
  "np_hkdf",
  "rand 0.8.5",
  "rand_ext",
+ "rand_pcg",
  "serde_json",
  "test_helper",
  "xts_aes",
@@ -1407,39 +1410,53 @@
 
 [[package]]
 name = "protobuf"
-version = "2.28.0"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
-
-[[package]]
-name = "protobuf-codegen"
-version = "2.28.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6"
+checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e"
 dependencies = [
- "protobuf",
+ "once_cell",
+ "protobuf-support",
+ "thiserror",
 ]
 
 [[package]]
-name = "protoc"
-version = "2.28.0"
+name = "protobuf-codegen"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0218039c514f9e14a5060742ecd50427f8ac4f85a6dc58f2ddb806e318c55ee"
+checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901"
 dependencies = [
+ "anyhow",
+ "once_cell",
+ "protobuf",
+ "protobuf-parse",
+ "regex",
+ "tempfile",
+ "thiserror",
+]
+
+[[package]]
+name = "protobuf-parse"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49"
+dependencies = [
+ "anyhow",
+ "indexmap",
  "log",
+ "protobuf",
+ "protobuf-support",
+ "tempfile",
+ "thiserror",
  "which",
 ]
 
 [[package]]
-name = "protoc-rust"
-version = "2.28.0"
+name = "protobuf-support"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22f8a182bb17c485f20bdc4274a8c39000a61024cfe461c799b50fec77267838"
+checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372"
 dependencies = [
- "protobuf",
- "protobuf-codegen",
- "protoc",
- "tempfile",
+ "thiserror",
 ]
 
 [[package]]
@@ -1775,9 +1792,9 @@
 
 [[package]]
 name = "spin"
-version = "0.9.7"
+version = "0.9.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0959fd6f767df20b231736396e4f602171e00d95205676286e79d4a4eb67bef"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
 dependencies = [
  "lock_api",
 ]
@@ -1899,7 +1916,7 @@
  "log",
  "rand 0.8.5",
  "rand_chacha 0.3.1",
- "spin 0.9.7",
+ "spin 0.9.8",
  "ukey2_connections",
  "ukey2_rs",
 ]
@@ -1931,7 +1948,7 @@
  "log",
  "rand 0.8.5",
  "rand_chacha 0.3.1",
- "spin 0.9.7",
+ "spin 0.9.8",
  "ukey2_connections",
  "ukey2_rs",
 ]
@@ -1942,7 +1959,7 @@
 dependencies = [
  "diff",
  "protobuf",
- "protoc-rust",
+ "protobuf-codegen",
 ]
 
 [[package]]
diff --git a/nearby/Cargo.toml b/nearby/Cargo.toml
index eabca53..a5570a8 100644
--- a/nearby/Cargo.toml
+++ b/nearby/Cargo.toml
@@ -62,10 +62,11 @@
 p256 = { version = "0.12.0", default-features = false }
 sec1 = "0.3.0"
 # AOSP's protobuf is only at 2.27.1 (http://cs/android-internal/external/rust/crates/protobuf/METADATA)
-protobuf = "2.27.1"
+protobuf = "3.2.0"
+protobuf-codegen = "3.2.0"
 protoc-rust = "2.27.1"
 jni = "0.21.1"
-spin = "0.9.4"
+spin = "0.9.8"
 anyhow = "1.0.64"
 log = "0.4.17"
 env_logger = "0.10.0"
diff --git a/nearby/connections/ukey2/ukey2/src/proto_adapter.rs b/nearby/connections/ukey2/ukey2/src/proto_adapter.rs
index 0660595..adb9982 100644
--- a/nearby/connections/ukey2/ukey2/src/proto_adapter.rs
+++ b/nearby/connections/ukey2/ukey2/src/proto_adapter.rs
@@ -18,12 +18,11 @@
 use crypto_provider::p256::{P256EcdhProvider, P256PublicKey, P256};
 use crypto_provider::CryptoProvider;
 use derive_getters::Getters;
-use ukey2_proto::protobuf::ProtobufEnum;
 use ukey2_proto::ukey2_all_proto::{securemessage, ukey};
 
 /// For generated proto types for UKEY2 messages
 trait WithMessageType: ukey2_proto::protobuf::Message {
-    fn msg_type() -> ukey::Ukey2Message_Type;
+    fn msg_type() -> ukey::ukey2message::Type;
 }
 
 pub(crate) trait ToWrappedMessage {
@@ -35,41 +34,42 @@
 
 impl<M: WithMessageType> ToWrappedMessage for M {
     fn to_wrapped_msg(self) -> ukey::Ukey2Message {
-        let mut message = ukey::Ukey2Message::default();
-        message.set_message_type(Self::msg_type());
-        message.set_message_data(self.write_to_bytes().unwrap());
-        message
+        ukey::Ukey2Message {
+            message_type: Some(Self::msg_type().into()),
+            message_data: self.write_to_bytes().ok(),
+            ..Default::default()
+        }
     }
 }
 
 impl WithMessageType for ukey::Ukey2Alert {
-    fn msg_type() -> ukey::Ukey2Message_Type {
-        ukey::Ukey2Message_Type::ALERT
+    fn msg_type() -> ukey::ukey2message::Type {
+        ukey::ukey2message::Type::ALERT
     }
 }
 
 impl WithMessageType for ukey::Ukey2ServerInit {
-    fn msg_type() -> ukey::Ukey2Message_Type {
-        ukey::Ukey2Message_Type::SERVER_INIT
+    fn msg_type() -> ukey::ukey2message::Type {
+        ukey::ukey2message::Type::SERVER_INIT
     }
 }
 
 impl WithMessageType for ukey::Ukey2ClientFinished {
-    fn msg_type() -> ukey::Ukey2Message_Type {
-        ukey::Ukey2Message_Type::CLIENT_FINISH
+    fn msg_type() -> ukey::ukey2message::Type {
+        ukey::ukey2message::Type::CLIENT_FINISH
     }
 }
 
 impl WithMessageType for ukey::Ukey2ClientInit {
-    fn msg_type() -> ukey::Ukey2Message_Type {
-        ukey::Ukey2Message_Type::CLIENT_INIT
+    fn msg_type() -> ukey::ukey2message::Type {
+        ukey::ukey2message::Type::CLIENT_INIT
     }
 }
 
 /// Convert a generated proto type into our custom adapter type.
 pub(crate) trait IntoAdapter<A> {
     /// Convert `self` into the adapter type.
-    fn into_adapter(self) -> Result<A, ukey::Ukey2Alert_AlertType>;
+    fn into_adapter(self) -> Result<A, ukey::ukey2alert::AlertType>;
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -125,53 +125,45 @@
     commitment: Vec<u8>,
 }
 
-pub(crate) enum PublicKeyType {
-    Ec256,
-    RSA2048,
-    Dh2048Modp,
-}
-
 pub(crate) enum GenericPublicKey<C: CryptoProvider> {
     Ec256(<C::P256 as EcdhProvider<P256>>::PublicKey),
     // Other public key types are not supported
 }
 
-impl IntoAdapter<MessageType> for i32 {
-    fn into_adapter(self) -> Result<MessageType, ukey::Ukey2Alert_AlertType> {
-        const CLIENT_INIT: i32 = ukey::Ukey2Message_Type::CLIENT_INIT as i32;
-        const SERVER_INIT: i32 = ukey::Ukey2Message_Type::SERVER_INIT as i32;
-        const CLIENT_FINISH: i32 = ukey::Ukey2Message_Type::CLIENT_FINISH as i32;
+impl IntoAdapter<MessageType> for ukey::ukey2message::Type {
+    fn into_adapter(self) -> Result<MessageType, ukey::ukey2alert::AlertType> {
         match self {
-            CLIENT_INIT => Some(MessageType::ClientInit),
-            SERVER_INIT => Some(MessageType::ServerInit),
-            CLIENT_FINISH => Some(MessageType::ClientFinish),
-            _ => None,
+            ukey::ukey2message::Type::CLIENT_INIT => Ok(MessageType::ClientInit),
+            ukey::ukey2message::Type::SERVER_INIT => Ok(MessageType::ServerInit),
+            ukey::ukey2message::Type::CLIENT_FINISH => Ok(MessageType::ClientFinish),
+            _ => Err(ukey::ukey2alert::AlertType::BAD_MESSAGE_TYPE),
         }
-        .ok_or(ukey::Ukey2Alert_AlertType::BAD_MESSAGE_TYPE)
     }
 }
 
 impl IntoAdapter<HandshakeCipher> for i32 {
-    fn into_adapter(self) -> Result<HandshakeCipher, ukey::Ukey2Alert_AlertType> {
+    fn into_adapter(self) -> Result<HandshakeCipher, ukey::ukey2alert::AlertType> {
         const P256_CODE: i32 = ukey::Ukey2HandshakeCipher::P256_SHA512 as i32;
         const CURVE25519_CODE: i32 = ukey::Ukey2HandshakeCipher::CURVE25519_SHA512 as i32;
         match self {
             P256_CODE => Ok(HandshakeCipher::P256Sha512),
             CURVE25519_CODE => Ok(HandshakeCipher::Curve25519Sha512),
-            _ => Err(ukey::Ukey2Alert_AlertType::BAD_HANDSHAKE_CIPHER),
+            _ => Err(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER),
         }
     }
 }
 
-impl IntoAdapter<CipherCommitment> for ukey::Ukey2ClientInit_CipherCommitment {
-    fn into_adapter(self) -> Result<CipherCommitment, ukey::Ukey2Alert_AlertType> {
-        let handshake_cipher: HandshakeCipher =
-            self.get_handshake_cipher().value().into_adapter()?;
+impl IntoAdapter<CipherCommitment> for ukey::ukey2client_init::CipherCommitment {
+    fn into_adapter(self) -> Result<CipherCommitment, ukey::ukey2alert::AlertType> {
+        let handshake_cipher: HandshakeCipher = self
+            .handshake_cipher
+            .ok_or(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER)
+            .and_then(|code| code.value().into_adapter())?;
         // no bad commitment so this is best-effort
-        let commitment = self.get_commitment().to_vec();
-        if commitment.is_empty() {
-            return Err(ukey::Ukey2Alert_AlertType::BAD_HANDSHAKE_CIPHER);
-        }
+        let commitment = self
+            .commitment
+            .filter(|c| !c.is_empty())
+            .ok_or(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER)?;
         Ok(CipherCommitment {
             commitment,
             cipher: handshake_cipher,
@@ -180,18 +172,17 @@
 }
 
 impl IntoAdapter<ClientInit> for ukey::Ukey2ClientInit {
-    fn into_adapter(self) -> Result<ClientInit, ukey::Ukey2Alert_AlertType> {
-        if self.get_random().len() != 32 {
-            return Err(ukey::Ukey2Alert_AlertType::BAD_RANDOM);
+    fn into_adapter(self) -> Result<ClientInit, ukey::ukey2alert::AlertType> {
+        if self.random().len() != 32 {
+            return Err(ukey::ukey2alert::AlertType::BAD_RANDOM);
         }
-        if !self.has_version() {
-            return Err(ukey::Ukey2Alert_AlertType::BAD_VERSION);
-        }
-        let version: i32 = self.get_version();
-        let next_protocol = String::from(self.get_next_protocol());
-        if next_protocol.is_empty() {
-            return Err(ukey::Ukey2Alert_AlertType::BAD_NEXT_PROTOCOL);
-        }
+        let version: i32 = self
+            .version
+            .ok_or(ukey::ukey2alert::AlertType::BAD_VERSION)?;
+        let next_protocol = self
+            .next_protocol
+            .filter(|n| !n.is_empty())
+            .ok_or(ukey::ukey2alert::AlertType::BAD_NEXT_PROTOCOL)?;
         Ok(ClientInit {
             next_protocol,
             version,
@@ -205,21 +196,22 @@
 }
 
 impl IntoAdapter<ServerInit> for ukey::Ukey2ServerInit {
-    fn into_adapter(self) -> Result<ServerInit, ukey::Ukey2Alert_AlertType> {
-        if !self.has_version() {
-            return Err(ukey::Ukey2Alert_AlertType::BAD_VERSION);
-        }
-        let version: i32 = self.get_version();
+    fn into_adapter(self) -> Result<ServerInit, ukey::ukey2alert::AlertType> {
+        let version: i32 = self
+            .version
+            .ok_or(ukey::ukey2alert::AlertType::BAD_VERSION)?;
         let random: [u8; 32] = self
-            .get_random()
-            .try_into()
-            .map_err(|_| ukey::Ukey2Alert_AlertType::BAD_RANDOM)?;
-        let handshake_cipher = self.get_handshake_cipher().value().into_adapter()?;
+            .random
+            .and_then(|r| r.try_into().ok())
+            .ok_or(ukey::ukey2alert::AlertType::BAD_RANDOM)?;
+        let handshake_cipher = self
+            .handshake_cipher
+            .ok_or(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER)
+            .and_then(|code| code.value().into_adapter())?;
         // We will be handling bad pubkeys in the layers above
-        let public_key: Vec<u8> = self.get_public_key().to_vec();
-        if public_key.is_empty() {
-            return Err(ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY);
-        }
+        let public_key: Vec<u8> = self
+            .public_key
+            .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
         Ok(ServerInit {
             handshake_cipher,
             version,
@@ -230,50 +222,45 @@
 }
 
 impl IntoAdapter<ClientFinished> for ukey::Ukey2ClientFinished {
-    fn into_adapter(self) -> Result<ClientFinished, ukey::Ukey2Alert_AlertType> {
-        let public_key: Vec<u8> = self.get_public_key().to_vec();
-        if public_key.is_empty() {
-            return Err(ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY);
-        }
+    fn into_adapter(self) -> Result<ClientFinished, ukey::ukey2alert::AlertType> {
+        let public_key: Vec<u8> = self
+            .public_key
+            .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
         Ok(ClientFinished { public_key })
     }
 }
 
 impl<C: CryptoProvider> IntoAdapter<GenericPublicKey<C>> for securemessage::GenericPublicKey {
-    fn into_adapter(self) -> Result<GenericPublicKey<C>, ukey::Ukey2Alert_AlertType> {
-        const DH2048_MODP: i32 = securemessage::PublicKeyType::DH2048_MODP as i32;
-        const EC_P256: i32 = securemessage::PublicKeyType::EC_P256 as i32;
-        const RSA_2048: i32 = securemessage::PublicKeyType::RSA2048 as i32;
-        let key_type = match self.get_field_type().value() {
-            DH2048_MODP => Some(PublicKeyType::Dh2048Modp),
-            EC_P256 => Some(PublicKeyType::Ec256),
-            RSA_2048 => Some(PublicKeyType::RSA2048),
-            _ => None,
-        }
-        .ok_or(ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY)?;
+    fn into_adapter(self) -> Result<GenericPublicKey<C>, ukey::ukey2alert::AlertType> {
+        let key_type = self
+            .type_
+            .and_then(|t| t.enum_value().ok())
+            .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
         match key_type {
-            PublicKeyType::Ec256 => {
-                let key = self.ec_p256_public_key.unwrap();
-                let key_x_bytes: [u8; 32] =
-                    positive_twos_complement_to_32_byte_unsigned(key.get_x())
-                        .ok_or(ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY)?;
-                let key_y_bytes: [u8; 32] =
-                    positive_twos_complement_to_32_byte_unsigned(key.get_y())
-                        .ok_or(ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY)?;
+            securemessage::PublicKeyType::EC_P256 => {
+                let (key_x, key_y) = self
+                    .ec_p256_public_key
+                    .into_option()
+                    .and_then(|pk| pk.x.zip(pk.y))
+                    .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
+                let key_x_bytes: [u8; 32] = positive_twos_complement_to_32_byte_unsigned(&key_x)
+                    .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
+                let key_y_bytes: [u8; 32] = positive_twos_complement_to_32_byte_unsigned(&key_y)
+                    .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
                 <C::P256 as P256EcdhProvider>::PublicKey::from_affine_coordinates(
                     &key_x_bytes,
                     &key_y_bytes,
                 )
                 .map(GenericPublicKey::Ec256)
-                .map_err(|_| ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY)
+                .map_err(|_| ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)
             }
-            PublicKeyType::RSA2048 => {
+            securemessage::PublicKeyType::RSA2048 => {
                 // We don't support RSA keys
-                Err(ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY)
+                Err(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)
             }
-            PublicKeyType::Dh2048Modp => {
+            securemessage::PublicKeyType::DH2048_MODP => {
                 // We don't support DH2048 keys, only ECDH.
-                Err(ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY)
+                Err(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)
             }
         }
     }
diff --git a/nearby/connections/ukey2/ukey2/src/state_machine.rs b/nearby/connections/ukey2/ukey2/src/state_machine.rs
index d381083..6b9a367 100644
--- a/nearby/connections/ukey2/ukey2/src/state_machine.rs
+++ b/nearby/connections/ukey2/ukey2/src/state_machine.rs
@@ -21,28 +21,28 @@
 use crypto_provider::CryptoProvider;
 use log::error;
 use std::fmt::Debug;
-use ukey2_proto::protobuf::{Message, ProtobufEnum};
+use ukey2_proto::protobuf::Message;
 use ukey2_proto::ukey2_all_proto::ukey;
 
 /// An alert type and message to be sent to the other party.
 #[derive(Debug, PartialEq, Eq)]
 pub struct SendAlert {
-    alert_type: ukey::Ukey2Alert_AlertType,
+    alert_type: ukey::ukey2alert::AlertType,
     msg: Option<String>,
 }
 
 impl SendAlert {
-    pub(crate) fn from(alert_type: ukey::Ukey2Alert_AlertType, msg: Option<String>) -> Self {
+    pub(crate) fn from(alert_type: ukey::ukey2alert::AlertType, msg: Option<String>) -> Self {
         Self { alert_type, msg }
     }
 
     /// Convert this `SendAlert` into serialized bytes of the `Ukey2Alert` protobuf message.
     pub fn into_wrapped_alert_msg(self) -> Vec<u8> {
-        let mut alert_message = ukey::Ukey2Alert::default();
-        alert_message.set_field_type(self.alert_type);
-        if let Some(msg) = self.msg {
-            alert_message.set_error_message(msg)
-        }
+        let alert_message = ukey::Ukey2Alert {
+            type_: Some(self.alert_type.into()),
+            error_message: self.msg,
+            ..Default::default()
+        };
         alert_message.to_wrapped_msg().write_to_bytes().unwrap()
     }
 }
@@ -102,7 +102,7 @@
         match message_type {
             // Client should not be receiving ClientInit/ClientFinish
             MessageType::ClientInit | MessageType::ClientFinish => Err(SendAlert::from(
-                ukey::Ukey2Alert_AlertType::INCORRECT_MESSAGE,
+                ukey::ukey2alert::AlertType::INCORRECT_MESSAGE,
                 Some("wrong message".to_string()),
             )),
             MessageType::ServerInit => {
@@ -110,7 +110,7 @@
                 self.handle_server_init(message, message_bytes.to_vec())
                     .map_err(|_| {
                         SendAlert::from(
-                            ukey::Ukey2Alert_AlertType::BAD_MESSAGE_DATA,
+                            ukey::ukey2alert::AlertType::BAD_MESSAGE_DATA,
                             Some("bad message_data".to_string()),
                         )
                     })
@@ -137,13 +137,13 @@
                         SendAlert::from(
                             match e {
                                 ClientInitError::BadVersion => {
-                                    ukey::Ukey2Alert_AlertType::BAD_VERSION
+                                    ukey::ukey2alert::AlertType::BAD_VERSION
                                 }
                                 ClientInitError::BadHandshakeCipher => {
-                                    ukey::Ukey2Alert_AlertType::BAD_HANDSHAKE_CIPHER
+                                    ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER
                                 }
                                 ClientInitError::BadNextProtocol => {
-                                    ukey::Ukey2Alert_AlertType::BAD_NEXT_PROTOCOL
+                                    ukey::ukey2alert::AlertType::BAD_NEXT_PROTOCOL
                                 }
                             },
                             None,
@@ -151,7 +151,7 @@
                     })
             }
             MessageType::ClientFinish | MessageType::ServerInit => Err(SendAlert::from(
-                ukey::Ukey2Alert_AlertType::INCORRECT_MESSAGE,
+                ukey::ukey2alert::AlertType::INCORRECT_MESSAGE,
                 Some("wrong message".to_string()),
             )),
         }
@@ -173,25 +173,25 @@
                 self.handle_client_finished_msg(message, message_bytes)
                     .map_err(|e| match e {
                         ClientFinishedError::BadEd25519Key => SendAlert::from(
-                            ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY,
+                            ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY,
                             "Bad ED25519 Key".to_string().into(),
                         ),
                         ClientFinishedError::BadP256Key => SendAlert::from(
-                            ukey::Ukey2Alert_AlertType::BAD_PUBLIC_KEY,
+                            ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY,
                             "Bad P256 Key".to_string().into(),
                         ),
                         ClientFinishedError::UnknownCommitment => SendAlert::from(
-                            ukey::Ukey2Alert_AlertType::BAD_MESSAGE_DATA,
+                            ukey::ukey2alert::AlertType::BAD_MESSAGE_DATA,
                             "Unknown commitment".to_string().into(),
                         ),
                         ClientFinishedError::BadKeyExchange => SendAlert::from(
-                            ukey::Ukey2Alert_AlertType::INTERNAL_ERROR,
+                            ukey::ukey2alert::AlertType::INTERNAL_ERROR,
                             "Key exchange error".to_string().into(),
                         ),
                     })
             }
             MessageType::ClientInit | MessageType::ServerInit => Err(SendAlert::from(
-                ukey::Ukey2Alert_AlertType::INCORRECT_MESSAGE,
+                ukey::ukey2alert::AlertType::INCORRECT_MESSAGE,
                 "wrong message".to_string().into(),
             )),
         }
@@ -204,27 +204,26 @@
         .map_err(|_| {
             error!("Unable to marshal into Ukey2Message");
             SendAlert::from(
-                ukey::Ukey2Alert_AlertType::BAD_MESSAGE,
+                ukey::ukey2alert::AlertType::BAD_MESSAGE,
                 Some("Bad message data".to_string()),
             )
         })
         .and_then(|message| {
-            let message_data = message.get_message_data();
+            let message_data = message.message_data();
             if message_data.is_empty() {
                 return Err(SendAlert::from(
-                    ukey::Ukey2Alert_AlertType::BAD_MESSAGE_DATA,
+                    ukey::ukey2alert::AlertType::BAD_MESSAGE_DATA,
                     None,
                 ));
             }
-            let message_type = message.get_message_type();
-            if message_type == ukey::Ukey2Message_Type::UNKNOWN_DO_NOT_USE {
+            let message_type = message.message_type();
+            if message_type == ukey::ukey2message::Type::UNKNOWN_DO_NOT_USE {
                 return Err(SendAlert::from(
-                    ukey::Ukey2Alert_AlertType::BAD_MESSAGE_TYPE,
+                    ukey::ukey2alert::AlertType::BAD_MESSAGE_TYPE,
                     None,
                 ));
             }
             message_type
-                .value()
                 .into_adapter()
                 .map_err(|e| {
                     error!("Unknown UKEY2 Message Type");
@@ -246,7 +245,7 @@
                 "Unable to unmarshal message, check frame of the message you were trying to send"
             );
             SendAlert::from(
-                ukey::Ukey2Alert_AlertType::BAD_MESSAGE_DATA,
+                ukey::ukey2alert::AlertType::BAD_MESSAGE_DATA,
                 Some("frame error".to_string()),
             )
         })?
diff --git a/nearby/connections/ukey2/ukey2/src/tests.rs b/nearby/connections/ukey2/ukey2/src/tests.rs
index 5f47706..5f3b942 100644
--- a/nearby/connections/ukey2/ukey2/src/tests.rs
+++ b/nearby/connections/ukey2/ukey2/src/tests.rs
@@ -52,12 +52,13 @@
         <C::X25519 as EcdhProvider<X25519>>::PublicKey::from_bytes(&secret.public_key_bytes())
             .unwrap();
     let random: [u8; 32] = rng.gen();
-
-    let mut message_data: ukey::Ukey2ServerInit = ukey::Ukey2ServerInit::default();
-    message_data.set_version(1);
-    message_data.set_random(random.to_vec());
-    message_data.set_handshake_cipher(ukey::Ukey2HandshakeCipher::CURVE25519_SHA512);
-    message_data.set_public_key(public_key.to_bytes().to_vec());
+    let message_data: ukey::Ukey2ServerInit = ukey::Ukey2ServerInit {
+        version: Some(1),
+        random: Some(random.to_vec()),
+        handshake_cipher: Some(ukey::Ukey2HandshakeCipher::CURVE25519_SHA512.into()),
+        public_key: Some(public_key.to_bytes()),
+        ..Default::default()
+    };
 
     let _client = client1
         .advance_state(
@@ -96,14 +97,18 @@
     let cipher = HandshakeCipher::Curve25519Sha512;
     let client_random = rng.gen::<[u8; 32]>();
     let client_init_framed = {
-        let mut commitment = ukey::Ukey2ClientInit_CipherCommitment::default();
-        commitment.set_handshake_cipher(cipher.as_proto());
-        commitment.set_commitment(client_finished_hash);
-        let mut client_init = ukey::Ukey2ClientInit::default();
-        client_init.set_version(1);
-        client_init.set_random(client_random.to_vec());
-        client_init.set_cipher_commitments(vec![commitment].into());
-        client_init.set_next_protocol("AES_256_CBC-HMAC_SHA256".to_string());
+        let commitment = ukey::ukey2client_init::CipherCommitment {
+            handshake_cipher: Some(cipher.as_proto().into()),
+            commitment: Some(client_finished_hash),
+            ..Default::default()
+        };
+        let client_init = ukey::Ukey2ClientInit {
+            version: Some(1),
+            random: Some(client_random.to_vec()),
+            cipher_commitments: vec![commitment],
+            next_protocol: Some("AES_256_CBC-HMAC_SHA256".to_string()),
+            ..Default::default()
+        };
         client_init.to_wrapped_msg()
     };
     let server2 = server1
@@ -149,15 +154,19 @@
     let client_finished_hash = hasher.finalize().to_vec();
     let cipher = HandshakeCipher::P256Sha512;
     let client_init_framed = {
-        let mut commitment = ukey::Ukey2ClientInit_CipherCommitment::default();
-        commitment.set_handshake_cipher(cipher.as_proto());
-        commitment.set_commitment(client_finished_hash);
-        let mut client_init = ukey::Ukey2ClientInit::default();
-        client_init.set_version(1);
-        client_init.set_random(rng.gen::<[u8; 32]>().to_vec());
-        client_init.set_cipher_commitments(vec![commitment].into());
-        client_init.set_next_protocol("AES_256_CBC-HMAC_SHA256".to_string());
-        client_init.to_wrapped_msg()
+        let commitment = ukey::ukey2client_init::CipherCommitment {
+            handshake_cipher: Some(cipher.as_proto().into()),
+            commitment: Some(client_finished_hash),
+            ..Default::default()
+        };
+        ukey::Ukey2ClientInit {
+            version: Some(1),
+            random: Some(rng.gen::<[u8; 32]>().to_vec()),
+            cipher_commitments: vec![commitment],
+            next_protocol: Some("AES_256_CBC-HMAC_SHA256".to_string()),
+            ..Default::default()
+        }
+        .to_wrapped_msg()
     };
     let server2 = server1
         .advance_state(&mut rng, &client_init_framed.write_to_bytes().unwrap())
@@ -171,10 +180,10 @@
 
 #[test]
 fn message_type_discriminant() {
-    assert_eq!(1, ukey::Ukey2Message_Type::ALERT as i32);
-    assert_eq!(2, ukey::Ukey2Message_Type::CLIENT_INIT as i32);
-    assert_eq!(3, ukey::Ukey2Message_Type::SERVER_INIT as i32);
-    assert_eq!(4, ukey::Ukey2Message_Type::CLIENT_FINISH as i32);
+    assert_eq!(1, ukey::ukey2message::Type::ALERT as i32);
+    assert_eq!(2, ukey::ukey2message::Type::CLIENT_INIT as i32);
+    assert_eq!(3, ukey::ukey2message::Type::SERVER_INIT as i32);
+    assert_eq!(4, ukey::ukey2message::Type::CLIENT_FINISH as i32);
 }
 
 #[test]
@@ -185,9 +194,24 @@
 
 #[test]
 fn convert_to_message_type() {
-    assert_eq!(MessageType::ClientInit, 2.into_adapter().unwrap());
-    assert_eq!(MessageType::ServerInit, 3.into_adapter().unwrap());
-    assert_eq!(MessageType::ClientFinish, 4.into_adapter().unwrap());
+    assert_eq!(
+        MessageType::ClientInit,
+        ukey::ukey2message::Type::CLIENT_INIT
+            .into_adapter()
+            .unwrap()
+    );
+    assert_eq!(
+        MessageType::ServerInit,
+        ukey::ukey2message::Type::SERVER_INIT
+            .into_adapter()
+            .unwrap()
+    );
+    assert_eq!(
+        MessageType::ClientFinish,
+        ukey::ukey2message::Type::CLIENT_FINISH
+            .into_adapter()
+            .unwrap()
+    );
 }
 
 #[test]
diff --git a/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs b/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs
index e5e0cb9..ec88318 100644
--- a/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs
+++ b/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs
@@ -99,12 +99,16 @@
                         num_bigint::Sign::Plus,
                         num_bigint::BigUint::from_bytes_be(y.to_vec().as_slice()),
                     );
-                    let mut proto_key = securemessage::EcP256PublicKey::default();
-                    proto_key.set_x(bigboi_x.to_signed_bytes_be());
-                    proto_key.set_y(bigboi_y.to_signed_bytes_be());
-                    let mut key = securemessage::GenericPublicKey::default();
-                    key.set_field_type(securemessage::PublicKeyType::EC_P256);
-                    key.set_ec_p256_public_key(proto_key);
+                    let proto_key = securemessage::EcP256PublicKey {
+                        x: Some(bigboi_x.to_signed_bytes_be()),
+                        y: Some(bigboi_y.to_signed_bytes_be()),
+                        ..Default::default()
+                    };
+                    let key = securemessage::GenericPublicKey {
+                        type_: Some(securemessage::PublicKeyType::EC_P256.into()),
+                        ec_p256_public_key: Some(proto_key).into(),
+                        ..Default::default()
+                    };
                     key.write_to_bytes().ok()
                 }
                 HandshakeCipher::Curve25519Sha512 => None,
@@ -392,8 +396,10 @@
                 >>::Rng as CryptoRng>::new(),
             );
         let curve25519_client_finished_bytes = {
-            let mut client_finished = ukey::Ukey2ClientFinished::default();
-            client_finished.set_public_key(curve25519_secret.public_key_bytes());
+            let client_finished = ukey::Ukey2ClientFinished {
+                public_key: Some(curve25519_secret.public_key_bytes()),
+                ..Default::default()
+            };
             client_finished.to_wrapped_msg().write_to_bytes().unwrap()
         };
         let curve25519_client_finished_hash =
@@ -406,35 +412,42 @@
                         >>::Rng as CryptoRng>::new(),
                     );
         let p256_client_finished_bytes = {
-            let mut client_finished = ukey::Ukey2ClientFinished::default();
-            client_finished.set_public_key(
-                handshake_impl
-                    .encode_public_key::<C>(
-                        p256_secret.public_key_bytes(),
-                        HandshakeCipher::P256Sha512,
-                    )
-                    .unwrap(),
-            );
+            let client_finished = ukey::Ukey2ClientFinished {
+                public_key: Some(
+                    handshake_impl
+                        .encode_public_key::<C>(
+                            p256_secret.public_key_bytes(),
+                            HandshakeCipher::P256Sha512,
+                        )
+                        .unwrap(),
+                ),
+                ..Default::default()
+            };
             client_finished.to_wrapped_msg().write_to_bytes().unwrap()
         };
         let p256_client_finished_hash = C::Sha512::sha512(&p256_client_finished_bytes).to_vec();
 
         // ClientInit Message
         let client_init_bytes = {
-            let mut curve25519_commitment = ukey::Ukey2ClientInit_CipherCommitment::default();
-            curve25519_commitment
-                .set_handshake_cipher(HandshakeCipher::Curve25519Sha512.as_proto());
-            curve25519_commitment.set_commitment(curve25519_client_finished_hash);
+            let curve25519_commitment = ukey::ukey2client_init::CipherCommitment {
+                handshake_cipher: Some(HandshakeCipher::Curve25519Sha512.as_proto().into()),
+                commitment: Some(curve25519_client_finished_hash),
+                ..Default::default()
+            };
 
-            let mut p256_commitment = ukey::Ukey2ClientInit_CipherCommitment::default();
-            p256_commitment.set_handshake_cipher(HandshakeCipher::P256Sha512.as_proto());
-            p256_commitment.set_commitment(p256_client_finished_hash);
+            let p256_commitment = ukey::ukey2client_init::CipherCommitment {
+                handshake_cipher: Some(HandshakeCipher::P256Sha512.as_proto().into()),
+                commitment: Some(p256_client_finished_hash),
+                ..Default::default()
+            };
 
-            let mut client_init = ukey::Ukey2ClientInit::default();
-            client_init.set_version(1);
-            client_init.set_random(random);
-            client_init.set_cipher_commitments(vec![curve25519_commitment, p256_commitment].into());
-            client_init.set_next_protocol(next_protocol.to_string());
+            let client_init = ukey::Ukey2ClientInit {
+                version: Some(1),
+                random: Some(random),
+                cipher_commitments: vec![curve25519_commitment, p256_commitment],
+                next_protocol: Some(next_protocol.to_string()),
+                ..Default::default()
+            };
             client_init.to_wrapped_msg().write_to_bytes().unwrap()
         };
 
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml b/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml
index 117c9ab..ec58e9a 100644
--- a/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml
+++ b/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml
@@ -15,7 +15,7 @@
 log.workspace = true
 rand.workspace = true
 rand_chacha.workspace = true
-spin = "0.9.4"
+spin.workspace = true
 
 [features]
 default = ["rustcrypto"]
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs b/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs
index 25d8992..68d42c9 100644
--- a/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs
+++ b/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs
@@ -351,7 +351,7 @@
     arr: CFFIByteArray,
 ) -> CD2DRestoreConnectionContextV1Result {
     let saved_session = std::slice::from_raw_parts(arr.ptr, arr.len);
-    let ctx = D2DConnectionContextV1::from_saved_session(saved_session);
+    let ctx = D2DConnectionContextV1::from_saved_session::<CryptoProvider>(saved_session);
     if let Ok(conn_ctx) = ctx {
         let final_ctx = Box::new(conn_ctx);
         CD2DRestoreConnectionContextV1Result {
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock b/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock
index f97ed03..8f42dbe 100644
--- a/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock
+++ b/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.lock
@@ -40,6 +40,21 @@
 ]
 
 [[package]]
+name = "aho-corasick"
+version = "0.7.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
+
+[[package]]
 name = "arbitrary"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -68,15 +83,6 @@
 
 [[package]]
 name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "block-buffer"
 version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
@@ -94,12 +100,6 @@
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
 name = "bytes"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -161,7 +161,7 @@
 checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
  "zeroize",
 ]
@@ -173,7 +173,7 @@
 checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "typenum",
 ]
 
@@ -201,10 +201,9 @@
  "p256",
  "rand",
  "rand_chacha",
- "rand_core 0.6.4",
- "rand_core_05_adapter",
+ "rand_core",
  "sec1",
- "sha2 0.10.6",
+ "sha2",
  "subtle",
  "x25519-dalek",
 ]
@@ -220,15 +219,16 @@
 
 [[package]]
 name = "curve25519-dalek"
-version = "3.2.0"
+version = "4.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
+checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585"
 dependencies = [
- "byteorder",
- "digest 0.9.0",
- "rand_core 0.5.1",
+ "cfg-if",
+ "digest",
+ "fiat-crypto",
+ "packed_simd_2",
+ "platforms",
  "subtle",
- "zeroize",
 ]
 
 [[package]]
@@ -249,7 +249,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -260,16 +260,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
-]
-
-[[package]]
-name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -278,30 +269,30 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
- "block-buffer 0.10.4",
+ "block-buffer",
  "crypto-common",
  "subtle",
 ]
 
 [[package]]
 name = "ed25519"
-version = "1.5.3"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
 dependencies = [
  "signature",
 ]
 
 [[package]]
 name = "ed25519-dalek"
-version = "1.0.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a"
 dependencies = [
  "curve25519-dalek",
  "ed25519",
- "sha2 0.9.9",
- "zeroize",
+ "rand_core",
+ "sha2",
 ]
 
 [[package]]
@@ -318,12 +309,12 @@
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "digest 0.10.6",
+ "digest",
  "ff",
  "generic-array",
  "group",
  "hkdf",
- "rand_core 0.6.4",
+ "rand_core",
  "sec1",
  "subtle",
  "zeroize",
@@ -365,11 +356,17 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
 dependencies = [
- "rand_core 0.6.4",
+ "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.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -398,11 +395,17 @@
 checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
 dependencies = [
  "ff",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
 ]
 
 [[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
 name = "hermit-abi"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -423,7 +426,17 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.6",
+ "digest",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown",
 ]
 
 [[package]]
@@ -483,6 +496,12 @@
 ]
 
 [[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
+[[package]]
 name = "linux-raw-sys"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -572,6 +591,22 @@
 ]
 
 [[package]]
+name = "packed_simd_2"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
+dependencies = [
+ "cfg-if",
+ "libm",
+]
+
+[[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.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -600,48 +635,62 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.53"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "protobuf"
-version = "2.28.0"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
-
-[[package]]
-name = "protobuf-codegen"
-version = "2.28.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6"
+checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e"
 dependencies = [
- "protobuf",
+ "once_cell",
+ "protobuf-support",
+ "thiserror",
 ]
 
 [[package]]
-name = "protoc"
-version = "2.28.0"
+name = "protobuf-codegen"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0218039c514f9e14a5060742ecd50427f8ac4f85a6dc58f2ddb806e318c55ee"
+checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901"
 dependencies = [
+ "anyhow",
+ "once_cell",
+ "protobuf",
+ "protobuf-parse",
+ "regex",
+ "tempfile",
+ "thiserror",
+]
+
+[[package]]
+name = "protobuf-parse"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49"
+dependencies = [
+ "anyhow",
+ "indexmap",
  "log",
+ "protobuf",
+ "protobuf-support",
+ "tempfile",
+ "thiserror",
  "which",
 ]
 
 [[package]]
-name = "protoc-rust"
-version = "2.28.0"
+name = "protobuf-support"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22f8a182bb17c485f20bdc4274a8c39000a61024cfe461c799b50fec77267838"
+checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372"
 dependencies = [
- "protobuf",
- "protobuf-codegen",
- "protoc",
- "tempfile",
+ "thiserror",
 ]
 
 [[package]]
@@ -661,7 +710,7 @@
 dependencies = [
  "libc",
  "rand_chacha",
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
@@ -671,17 +720,11 @@
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-
-[[package]]
-name = "rand_core"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
@@ -690,14 +733,6 @@
 ]
 
 [[package]]
-name = "rand_core_05_adapter"
-version = "0.1.0"
-dependencies = [
- "rand",
- "rand_core 0.5.1",
-]
-
-[[package]]
 name = "redox_syscall"
 version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -707,6 +742,23 @@
 ]
 
 [[package]]
+name = "regex"
+version = "1.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
 name = "rustix"
 version = "0.36.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -735,33 +787,20 @@
 
 [[package]]
 name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
-
-[[package]]
-name = "sha2"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
 name = "signature"
-version = "1.6.4"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
 
 [[package]]
 name = "subtle"
@@ -781,15 +820,14 @@
 ]
 
 [[package]]
-name = "synstructure"
-version = "0.12.6"
+name = "syn"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
+checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
- "unicode-xid",
+ "unicode-ident",
 ]
 
 [[package]]
@@ -806,6 +844,26 @@
 ]
 
 [[package]]
+name = "thiserror"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.13",
+]
+
+[[package]]
 name = "typenum"
 version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -840,7 +898,7 @@
 version = "0.1.0"
 dependencies = [
  "protobuf",
- "protoc-rust",
+ "protobuf-codegen",
 ]
 
 [[package]]
@@ -862,12 +920,6 @@
 checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
 
 [[package]]
-name = "unicode-xid"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
-
-[[package]]
 name = "universal-hash"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1005,13 +1057,12 @@
 
 [[package]]
 name = "x25519-dalek"
-version = "2.0.0-pre.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df"
+checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95"
 dependencies = [
  "curve25519-dalek",
- "rand_core 0.6.4",
- "zeroize",
+ "rand_core",
 ]
 
 [[package]]
@@ -1019,18 +1070,3 @@
 version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs
index a301c47..1db7e63 100644
--- a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs
+++ b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs
@@ -13,7 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-
 use arbitrary::Arbitrary;
 use crypto_provider_rustcrypto::RustCrypto;
 use libfuzzer_sys::fuzz_target;
@@ -27,6 +26,8 @@
 enum Type {
     SentByInitiator,
     SentByServer,
+    ReceivedByInitiator,
+    ReceivedByServer,
 }
 
 #[derive(Debug, Arbitrary)]
@@ -103,6 +104,16 @@
                     .unwrap();
                 assert_eq!(decoded, payload);
             }
+            Type::ReceivedByInitiator => {
+                // Both Ok and Err results are possible here since the input is Arbitrary payload
+                let _unused_result = initiator_connection
+                    .decode_message_from_peer::<RustCrypto, _>(&payload, associated_data);
+            }
+            Type::ReceivedByServer => {
+                // Both Ok and Err results are possible here since the input is Arbitrary payload
+                let _unused_result = server_connection
+                    .decode_message_from_peer::<RustCrypto, _>(&payload, associated_data);
+            }
         }
     }
 });
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs
index a8e1d4e..c2cd385 100644
--- a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs
+++ b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs
@@ -13,21 +13,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-
 use libfuzzer_sys::fuzz_target;
-use ukey2_connections::{
-    DeserializeError, D2DConnectionContextV1
-};
+use ukey2_connections::{D2DConnectionContextV1, DeserializeError};
+use crypto_provider_rustcrypto::RustCrypto;
 
 const PROTOCOL_VERSION: u8 = 1;
 
 fuzz_target!(|input: [u8; 73]| {
-    let result = D2DConnectionContextV1::from_saved_session(&input);
+    let result = D2DConnectionContextV1::from_saved_session::<RustCrypto>(&input);
     if input[0] != PROTOCOL_VERSION {
-        assert_eq!(
-            result.unwrap_err(),
-            DeserializeError::BadProtocolVersion
-        );
+        assert_eq!(result.unwrap_err(), DeserializeError::BadProtocolVersion);
     } else {
         assert!(result.is_ok());
     }
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs
index 97012ba..3007c9a 100644
--- a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs
+++ b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs
@@ -13,7 +13,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-
 use arbitrary::Arbitrary;
 use crypto_provider_rustcrypto::RustCrypto;
 use libfuzzer_sys::fuzz_target;
diff --git a/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs b/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs
index 97e950a..1f524c9 100644
--- a/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs
+++ b/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs
@@ -77,11 +77,10 @@
 
 // Static utility functions for dealing with DeviceToDeviceMessage.
 fn create_device_to_device_message(msg: RustDeviceToDeviceMessage) -> Vec<u8> {
-    let d2d_message = {
-        let mut proto_msg = DeviceToDeviceMessage::default();
-        proto_msg.set_message(msg.message);
-        proto_msg.set_sequence_number(msg.sequence_num);
-        proto_msg
+    let d2d_message = DeviceToDeviceMessage {
+        message: Some(msg.message),
+        sequence_number: Some(msg.sequence_num),
+        ..Default::default()
     };
     d2d_message.write_to_bytes().unwrap()
 }
@@ -91,8 +90,10 @@
 ) -> Result<RustDeviceToDeviceMessage, DecodeError> {
     let result =
         DeviceToDeviceMessage::parse_from_bytes(message).map_err(|_| DecodeError::BadData)?;
-    let msg = result.get_message().to_vec();
-    let seq_num = result.get_sequence_number();
+    let (msg, seq_num) = result
+        .message
+        .zip(result.sequence_number)
+        .ok_or(DecodeError::BadData)?;
     Ok(RustDeviceToDeviceMessage {
         sequence_num: seq_num,
         message: msg,
@@ -118,6 +119,10 @@
     encode_sequence_num: i32,
     encode_key: Aes256Key,
     decode_key: Aes256Key,
+    encryption_key: Aes256Key,
+    decryption_key: Aes256Key,
+    signing_key: Aes256Key,
+    verify_key: Aes256Key,
     rng: R,
 }
 
@@ -152,8 +157,8 @@
 }
 
 impl D2DConnectionContextV1<rand::rngs::StdRng> {
-    pub fn from_saved_session(session: &[u8]) -> Result<Self, DeserializeError> {
-        Self::from_saved_session_with_rng(session, rand::rngs::StdRng::from_entropy())
+    pub fn from_saved_session<C: CryptoProvider>(session: &[u8]) -> Result<Self, DeserializeError> {
+        Self::from_saved_session_with_rng::<C>(session, rand::rngs::StdRng::from_entropy())
     }
 }
 
@@ -163,18 +168,26 @@
 {
     pub(crate) const NEXT_PROTOCOL_IDENTIFIER: &'static str = "AES_256_CBC-HMAC_SHA256";
 
-    pub fn new(
+    pub fn new<C: CryptoProvider>(
         decode_sequence_num: i32,
         encode_sequence_num: i32,
         encode_key: Aes256Key,
         decode_key: Aes256Key,
         rng: R,
     ) -> Self {
+        let encryption_key = derive_aes256_key::<C>(&encode_key, b"ENC:2");
+        let decryption_key = derive_aes256_key::<C>(&decode_key, b"ENC:2");
+        let signing_key = derive_aes256_key::<C>(&encode_key, b"SIG:1");
+        let verify_key = derive_aes256_key::<C>(&decode_key, b"SIG:1");
         D2DConnectionContextV1 {
             decode_sequence_num,
             encode_sequence_num,
             encode_key,
             decode_key,
+            encryption_key,
+            decryption_key,
+            signing_key,
+            verify_key,
             rng,
         }
     }
@@ -187,7 +200,7 @@
             .next_protocol_secret::<C>()
             .derive_array::<AES_256_KEY_SIZE>()
             .unwrap();
-        D2DConnectionContextV1::new(
+        D2DConnectionContextV1::new::<C>(
             0,
             0,
             encryption_key::<32, C>(&next_protocol_secret, HKDF_INFO_KEY_INITIATOR).unwrap(),
@@ -204,7 +217,7 @@
             .next_protocol_secret::<C>()
             .derive_array::<AES_256_KEY_SIZE>()
             .unwrap();
-        D2DConnectionContextV1::new(
+        D2DConnectionContextV1::new::<C>(
             0,
             0,
             encryption_key::<32, C>(&next_protocol_secret, HKDF_INFO_KEY_RESPONDER).unwrap(),
@@ -240,7 +253,7 @@
         ret
     }
 
-    pub(crate) fn from_saved_session_with_rng(
+    pub(crate) fn from_saved_session_with_rng<C: CryptoProvider>(
         session: &[u8],
         rng: R,
     ) -> Result<Self, DeserializeError> {
@@ -268,13 +281,13 @@
             // This should always succeed since all of the parsers above are valid over the entire
             // [u8] space, and we already checked the length at the start.
             .expect("Saved session parsing should succeed");
-        Ok(Self {
+        Ok(Self::new::<C>(
             encode_sequence_num,
             decode_sequence_num,
             encode_key,
             decode_key,
             rng,
-        })
+        ))
     }
 
     /// Once initiator and responder have exchanged public keys, use this method to encrypt and
@@ -295,42 +308,46 @@
             message: payload.to_vec(),
             sequence_num: self.get_sequence_number_for_encoding(),
         });
-        let encrypt_key = derive_aes256_key::<C>(&self.encode_key, b"ENC:2");
         let (ciphertext, iv) = crypto_utils::encrypt::<_, C::AesCbcPkcs7Padded>(
-            &encrypt_key,
+            &self.encryption_key,
             message.as_slice(),
             &mut self.rng,
         );
-        let mut metadata: GcmMetadata = GcmMetadata::default();
-        metadata.set_field_type(Type::DEVICE_TO_DEVICE_MESSAGE);
-        // As specified in
-        // google3/third_party/ukey2/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java
-        metadata.set_version(1);
-        let mut header: Header = Header::default();
-        header.set_signature_scheme(SigScheme::HMAC_SHA256);
-        header.set_encryption_scheme(EncScheme::AES_256_CBC);
-        header.set_iv(iv.to_vec());
-        header.set_public_metadata(metadata.write_to_bytes().unwrap());
-        if let Some(assoc_data) = associated_data.as_ref() {
-            header.set_associated_data_length(assoc_data.as_ref().len() as u32)
-        }
-        let mut header_and_body = HeaderAndBody::default();
-        header_and_body.set_header(header);
-        header_and_body.set_body(ciphertext);
+        let metadata = GcmMetadata {
+            type_: Some(Type::DEVICE_TO_DEVICE_MESSAGE.into()),
+            // As specified in
+            // google3/third_party/ukey2/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java
+            version: Some(1),
+            ..Default::default()
+        };
+        let header = Header {
+            signature_scheme: Some(SigScheme::HMAC_SHA256.into()),
+            encryption_scheme: Some(EncScheme::AES_256_CBC.into()),
+            iv: Some(iv.to_vec()),
+            public_metadata: Some(metadata.write_to_bytes().unwrap()),
+            associated_data_length: associated_data.as_ref().map(|d| d.as_ref().len() as u32),
+            ..Default::default()
+        };
+        let header_and_body = HeaderAndBody {
+            header: Some(header).into(),
+            body: Some(ciphertext),
+            ..Default::default()
+        };
         let header_and_body_bytes = header_and_body.write_to_bytes().unwrap();
 
         // add sha256 MAC
-        let sign_key = derive_aes256_key::<C>(&self.encode_key, b"SIG:1");
-        let mut hmac = C::HmacSha256::new_from_slice(&sign_key).unwrap();
+        let mut hmac = C::HmacSha256::new_from_slice(&self.signing_key).unwrap();
         hmac.update(header_and_body_bytes.as_slice());
         if let Some(associated_data_vec) = associated_data.as_ref() {
             hmac.update(associated_data_vec.as_ref())
         }
         let result_mac = hmac.finalize().to_vec();
 
-        let mut secure_message = SecureMessage::default();
-        secure_message.set_header_and_body(header_and_body_bytes);
-        secure_message.set_signature(result_mac);
+        let secure_message = SecureMessage {
+            header_and_body: Some(header_and_body_bytes),
+            signature: Some(result_mac),
+            ..Default::default()
+        };
         secure_message.write_to_bytes().unwrap()
     }
 
@@ -349,37 +366,36 @@
         // first confirm that the payload MAC matches the header_and_body
         let message = SecureMessage::parse_from_bytes(payload).map_err(|_| DecodeError::BadData)?;
         let payload_mac: [u8; 32] = message
-            .get_signature()
-            .try_into()
-            .map_err(|_| DecodeError::BadData)?;
-        let payload = message.get_header_and_body();
-        let verify_key = derive_aes256_key::<C>(&self.decode_key, b"SIG:1");
-        let mut hmac = C::HmacSha256::new_from_slice(&verify_key).unwrap();
-        hmac.update(payload);
+            .signature
+            .and_then(|signature| signature.try_into().ok())
+            .ok_or(DecodeError::BadData)?;
+        let payload = message.header_and_body.ok_or(DecodeError::BadData)?;
+        let mut hmac = C::HmacSha256::new_from_slice(&self.verify_key).unwrap();
+        hmac.update(&payload);
         if let Some(associated_data) = associated_data.as_ref() {
             hmac.update(associated_data.as_ref())
         }
         hmac.verify(payload_mac).map_err(|_| DecodeError::BadData)?;
-        let payload = HeaderAndBody::parse_from_bytes(payload).map_err(|_| DecodeError::BadData)?;
-        let associated_data_len = payload.header.as_ref().and_then(|header| {
-            if header.has_associated_data_length() {
-                Some(header.get_associated_data_length())
-            } else {
-                None
-            }
-        });
+        let payload =
+            HeaderAndBody::parse_from_bytes(&payload).map_err(|_| DecodeError::BadData)?;
+        let associated_data_len = payload
+            .header
+            .as_ref()
+            .and_then(|header| header.associated_data_length);
         if associated_data_len != associated_data.map(|ad| ad.as_ref().len() as u32) {
             return Err(DecodeError::BadData);
         }
         let iv: AesCbcIv = payload
-            .get_header()
-            .get_iv()
-            .try_into()
-            .map_err(|_| DecodeError::BadData)?;
-        let decode_key = derive_aes256_key::<C>(&self.decode_key, b"ENC:2");
-        let decrypted =
-            crypto_utils::decrypt::<C::AesCbcPkcs7Padded>(&decode_key, payload.get_body(), &iv)
-                .map_err(|_| DecodeError::BadData)?;
+            .header
+            .as_ref()
+            .and_then(|header| header.iv().try_into().ok())
+            .ok_or(DecodeError::BadData)?;
+        let decrypted = crypto_utils::decrypt::<C::AesCbcPkcs7Padded>(
+            &self.decryption_key,
+            &payload.body.unwrap_or_default(),
+            &iv,
+        )
+        .map_err(|_| DecodeError::BadData)?;
         let d2d_message = unwrap_device_to_device_message(decrypted.as_slice())?;
         if d2d_message.sequence_num != self.get_sequence_number_for_decoding() + 1 {
             return Err(DecodeError::BadSequenceNumber);
diff --git a/nearby/connections/ukey2/ukey2_connections/src/tests.rs b/nearby/connections/ukey2/ukey2_connections/src/tests.rs
index db76b62..9b5403f 100644
--- a/nearby/connections/ukey2/ukey2_connections/src/tests.rs
+++ b/nearby/connections/ukey2/ukey2_connections/src/tests.rs
@@ -37,8 +37,7 @@
     let (ciphertext, iv) =
         encrypt::<_, C::AesCbcPkcs7Padded>(key, message, &mut rand::rngs::StdRng::from_entropy());
     let decrypt_result = decrypt::<C::AesCbcPkcs7Padded>(key, ciphertext.as_slice(), &iv);
-    assert!(decrypt_result.is_ok());
-    let ptext = decrypt_result.unwrap();
+    let ptext = decrypt_result.expect("Decrypt should be successful");
     assert_eq!(ptext, message.to_vec());
 }
 
@@ -146,7 +145,7 @@
 #[rstest]
 fn send_receive_message_seeded<C: CryptoProvider>(
     // TODO: Find a way to inject RNG / generated ephemeral secrets in openSSL and test them here
-    #[values(RustCryptoImpl::<MockRng>::new())] _crypto_provider: C,
+    #[values(RustCryptoImpl::< MockRng >::new())] _crypto_provider: C,
 ) {
     let rng = MockRng;
     let message = b"Hello World!";
@@ -179,8 +178,10 @@
     let (mut init_conn_ctx, mut server_conn_ctx) = run_handshake::<C>();
     let encoded = init_conn_ctx.encode_message_to_peer::<C, &[u8]>(message, None);
     let decoded = server_conn_ctx.decode_message_from_peer::<C, &[u8]>(encoded.as_slice(), None);
-    assert!(decoded.is_ok());
-    assert_eq!(message.to_vec(), decoded.unwrap());
+    assert_eq!(
+        message.to_vec(),
+        decoded.expect("Decode should be successful")
+    );
 }
 
 #[rstest]
@@ -192,8 +193,10 @@
     let encoded = init_conn_ctx.encode_message_to_peer::<C, _>(message, Some(b"associated data"));
     let decoded = server_conn_ctx
         .decode_message_from_peer::<C, _>(encoded.as_slice(), Some(b"associated data"));
-    assert!(decoded.is_ok());
-    assert_eq!(message.to_vec(), decoded.unwrap());
+    assert_eq!(
+        message.to_vec(),
+        decoded.expect("Decode should be successful")
+    );
     // Make sure decode fails with missing associated data.
     let decoded = server_conn_ctx.decode_message_from_peer::<C, &[u8]>(encoded.as_slice(), None);
     assert!(decoded.is_err());
@@ -210,17 +213,20 @@
     let (init_conn_ctx, server_conn_ctx) = run_handshake::<C>();
     let init_session = init_conn_ctx.save_session();
     let server_session = server_conn_ctx.save_session();
-    let mut init_restored_ctx = D2DConnectionContextV1::from_saved_session(init_session.as_slice())
-        .expect("failed to restore client session");
+    let mut init_restored_ctx =
+        D2DConnectionContextV1::from_saved_session::<C>(init_session.as_slice())
+            .expect("failed to restore client session");
     let mut server_restored_ctx =
-        D2DConnectionContextV1::from_saved_session(server_session.as_slice())
+        D2DConnectionContextV1::from_saved_session::<C>(server_session.as_slice())
             .expect("failed to restore server session");
     let message = b"Hello World!";
     let encoded = init_restored_ctx.encode_message_to_peer::<C, &[u8]>(message, None);
     let decoded =
         server_restored_ctx.decode_message_from_peer::<C, &[u8]>(encoded.as_slice(), None);
-    assert!(decoded.is_ok());
-    assert_eq!(message.to_vec(), decoded.unwrap());
+    assert_eq!(
+        message.to_vec(),
+        decoded.expect("Decode should be successful")
+    );
 }
 
 #[rstest]
@@ -230,9 +236,10 @@
     let (init_conn_ctx, server_conn_ctx) = run_handshake::<C>();
     let init_session = init_conn_ctx.save_session();
     let server_session = server_conn_ctx.save_session();
-    let _ = D2DConnectionContextV1::from_saved_session(init_session.as_slice())
+    let _ = D2DConnectionContextV1::from_saved_session::<C>(init_session.as_slice())
         .expect("failed to restore client session");
-    let server_restored_ctx = D2DConnectionContextV1::from_saved_session(&server_session[0..60]);
+    let server_restored_ctx =
+        D2DConnectionContextV1::from_saved_session::<C>(&server_session[0..60]);
     assert_eq!(
         server_restored_ctx.unwrap_err(),
         DeserializeError::BadDataLength
@@ -246,10 +253,10 @@
     let (init_conn_ctx, server_conn_ctx) = run_handshake::<C>();
     let init_session = init_conn_ctx.save_session();
     let mut server_session = server_conn_ctx.save_session();
-    let _ = D2DConnectionContextV1::from_saved_session(init_session.as_slice())
+    let _ = D2DConnectionContextV1::from_saved_session::<C>(init_session.as_slice())
         .expect("failed to restore client session");
     server_session[0] = 0; // Change the protocol version to an invalid one (0)
-    let server_restored_ctx = D2DConnectionContextV1::from_saved_session(&server_session);
+    let server_restored_ctx = D2DConnectionContextV1::from_saved_session::<C>(&server_session);
     assert_eq!(
         server_restored_ctx.unwrap_err(),
         DeserializeError::BadProtocolVersion
@@ -266,11 +273,13 @@
     let message = b"Hello World!";
     let encoded = init_conn_ctx.encode_message_to_peer::<C, &[u8]>(message, None);
     let decoded = server_conn_ctx.decode_message_from_peer::<C, &[u8]>(encoded.as_slice(), None);
-    assert!(decoded.is_ok());
-    assert_eq!(message.to_vec(), decoded.unwrap());
+    assert_eq!(
+        message.to_vec(),
+        decoded.expect("Decode should be successful")
+    );
     let init_session_after = init_conn_ctx.get_session_unique::<C>();
     let server_session_after = server_conn_ctx.get_session_unique::<C>();
-    let bad_server_ctx = D2DConnectionContextV1::new(
+    let bad_server_ctx = D2DConnectionContextV1::new::<C>(
         server_conn_ctx.get_sequence_number_for_decoding(),
         server_conn_ctx.get_sequence_number_for_encoding(),
         Aes256Key::default(),
diff --git a/nearby/connections/ukey2/ukey2_jni/src/lib.rs b/nearby/connections/ukey2/ukey2_jni/src/lib.rs
index 03cd24c..e5106d7 100644
--- a/nearby/connections/ukey2/ukey2_jni/src/lib.rs
+++ b/nearby/connections/ukey2/ukey2_jni/src/lib.rs
@@ -431,7 +431,8 @@
     let session_info_rust = env
         .convert_byte_array(unsafe { JByteArray::from_raw(session_info) })
         .expect("bad session_info data");
-    let ctx = D2DConnectionContextV1::from_saved_session(session_info_rust.as_slice());
+    let ctx =
+        D2DConnectionContextV1::from_saved_session::<CryptoProvider>(session_info_rust.as_slice());
     if ctx.is_err() {
         env.throw_new(
             "com/google/security/cryptauth/lib/securegcm/SessionRestoreException",
diff --git a/nearby/connections/ukey2/ukey2_proto/Cargo.toml b/nearby/connections/ukey2/ukey2_proto/Cargo.toml
index 6ac2f52..c94d5b8 100644
--- a/nearby/connections/ukey2/ukey2_proto/Cargo.toml
+++ b/nearby/connections/ukey2/ukey2_proto/Cargo.toml
@@ -16,5 +16,5 @@
 diff = "0.1.13"
 
 [build-dependencies]
-protoc-rust.workspace = true
+protobuf-codegen.workspace = true
 
diff --git a/nearby/connections/ukey2/ukey2_proto/build.rs b/nearby/connections/ukey2/ukey2_proto/build.rs
index 158b0b8..8d9aaa0 100644
--- a/nearby/connections/ukey2/ukey2_proto/build.rs
+++ b/nearby/connections/ukey2/ukey2_proto/build.rs
@@ -12,12 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use protoc_rust::Customize;
+use protobuf_codegen::Customize;
 
 fn main() {
-    let out_dir = std::env::var("OUT_DIR").unwrap() + "/proto";
-    std::fs::create_dir_all(&out_dir).unwrap();
-    protoc_rust::Codegen::new()
+    protobuf_codegen::Codegen::new()
+        .protoc()
         // All inputs and imports from the inputs must reside in `includes` directories.
         .includes(["proto"])
         // Inputs must reside in some of include paths.
@@ -25,11 +24,7 @@
         .input("proto/securemessage.proto")
         .input("proto/securegcm.proto")
         .input("proto/device_to_device_messages.proto")
-        .customize(Customize {
-            gen_mod_rs: Some(true),
-            ..Default::default()
-        })
-        .out_dir(out_dir)
-        .run()
-        .unwrap();
+        .customize(Customize::default().gen_mod_rs(true))
+        .cargo_out_dir("proto")
+        .run_from_script()
 }
diff --git a/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto b/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto
index aef2765..7a19739 100644
--- a/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto
+++ b/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto
@@ -36,6 +36,7 @@
   ECDSA_P256_SHA256 = 2;
   // Not recommended -- use ECDSA_P256_SHA256 instead
   RSA2048_SHA256 = 3;
+  AEAD = 4;
 }
 
 // Supported encryption schemes
@@ -43,6 +44,7 @@
   // No encryption
   NONE = 1;
   AES_256_CBC = 2;
+  AES_256_GCM_SIV = 3;
 }
 
 message Header {
@@ -59,6 +61,8 @@
   // The length of some associated data this is not sent in this SecureMessage,
   // but which will be bound to the signature.
   optional uint32 associated_data_length = 7 [default = 0];
+  // Encryption may use a nonce. Required for AES-256-GCM-SIV.
+  optional bytes nonce = 8;
 }
 
 message HeaderAndBody {
diff --git a/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto b/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto
index 2b4dcd5..1edec1f 100644
--- a/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto
+++ b/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto
@@ -87,6 +87,8 @@
 
   // Next protocol that the client wants to speak.
   optional string next_protocol = 4;
+  // Other next protocols the client can speak.
+  repeated string other_next_protocols = 5;
 }
 
 message Ukey2ServerInit {
@@ -97,6 +99,9 @@
   // Selected Cipher and corresponding public key
   optional Ukey2HandshakeCipher handshake_cipher = 3;
   optional bytes public_key = 4;
+  // The server-selected next_protocol string based on the Ukey2ClientInit's
+  // next_protocol string and other_next_protocols array.
+  optional string selected_next_protocol = 5;
 }
 
 message Ukey2ClientFinished {
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs
index e4d2a99..3c2da35 100644
--- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs
+++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs
@@ -12,7 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// This file is generated by rust-protobuf 2.28.0. Do not edit
+// This file is generated by rust-protobuf 3.2.0. Do not edit
+// .proto file is parsed by protoc 3.19.1
 // @generated
 
 // https://github.com/rust-lang/rust-clippy/issues/702
@@ -29,22 +30,27 @@
 #![allow(non_snake_case)]
 #![allow(non_upper_case_globals)]
 #![allow(trivial_casts)]
-#![allow(unused_imports)]
 #![allow(unused_results)]
+#![allow(unused_mut)]
+
 //! Generated file from `device_to_device_messages.proto`
+// Generated for lite runtime
 
 /// Generated files are compatible only with the same version
 /// of protobuf runtime.
-// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_28_0;
+const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.DeviceToDeviceMessage)
 pub struct DeviceToDeviceMessage {
     // message fields
-    message: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    sequence_number: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.DeviceToDeviceMessage.message)
+    pub message: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.DeviceToDeviceMessage.sequence_number)
+    pub sequence_number: ::std::option::Option<i32>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.DeviceToDeviceMessage.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a DeviceToDeviceMessage {
@@ -60,15 +66,15 @@
 
     // optional bytes message = 1;
 
-
-    pub fn get_message(&self) -> &[u8] {
+    pub fn message(&self) -> &[u8] {
         match self.message.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_message(&mut self) {
-        self.message.clear();
+        self.message = ::std::option::Option::None;
     }
 
     pub fn has_message(&self) -> bool {
@@ -77,14 +83,14 @@
 
     // Param is passed by value, moved
     pub fn set_message(&mut self, v: ::std::vec::Vec<u8>) {
-        self.message = ::protobuf::SingularField::some(v);
+        self.message = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_message(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.message.is_none() {
-            self.message.set_default();
+            self.message = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.message.as_mut().unwrap()
     }
@@ -96,10 +102,10 @@
 
     // optional int32 sequence_number = 2;
 
-
-    pub fn get_sequence_number(&self) -> i32 {
+    pub fn sequence_number(&self) -> i32 {
         self.sequence_number.unwrap_or(0)
     }
+
     pub fn clear_sequence_number(&mut self) {
         self.sequence_number = ::std::option::Option::None;
     }
@@ -115,26 +121,23 @@
 }
 
 impl ::protobuf::Message for DeviceToDeviceMessage {
+    const NAME: &'static str = "DeviceToDeviceMessage";
+
     fn is_initialized(&self) -> bool {
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.message)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    self.message = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.sequence_number = ::std::option::Option::Some(tmp);
+                16 => {
+                    self.sequence_number = ::std::option::Option::Some(is.read_int32()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -143,88 +146,69 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.message.as_ref() {
+        if let Some(v) = self.message.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1, &v);
         }
         if let Some(v) = self.sequence_number {
-            my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(2, v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.message.as_ref() {
-            os.write_bytes(1, &v)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.message.as_ref() {
+            os.write_bytes(1, v)?;
         }
         if let Some(v) = self.sequence_number {
             os.write_int32(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> DeviceToDeviceMessage {
         DeviceToDeviceMessage::new()
     }
 
-    fn default_instance() -> &'static DeviceToDeviceMessage {
-        static instance: ::protobuf::rt::LazyV2<DeviceToDeviceMessage> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(DeviceToDeviceMessage::new)
-    }
-}
-
-impl ::protobuf::Clear for DeviceToDeviceMessage {
     fn clear(&mut self) {
-        self.message.clear();
+        self.message = ::std::option::Option::None;
         self.sequence_number = ::std::option::Option::None;
-        self.unknown_fields.clear();
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for DeviceToDeviceMessage {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static DeviceToDeviceMessage {
+        static instance: DeviceToDeviceMessage = DeviceToDeviceMessage {
+            message: ::std::option::Option::None,
+            sequence_number: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.InitiatorHello)
 pub struct InitiatorHello {
     // message fields
-    pub public_dh_key: ::protobuf::SingularPtrField<super::securemessage::GenericPublicKey>,
-    protocol_version: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.InitiatorHello.public_dh_key)
+    pub public_dh_key: ::protobuf::MessageField<super::securemessage::GenericPublicKey>,
+    // @@protoc_insertion_point(field:securegcm.InitiatorHello.protocol_version)
+    pub protocol_version: ::std::option::Option<i32>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.InitiatorHello.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a InitiatorHello {
@@ -238,45 +222,12 @@
         ::std::default::Default::default()
     }
 
-    // optional .securemessage.GenericPublicKey public_dh_key = 1;
-
-
-    pub fn get_public_dh_key(&self) -> &super::securemessage::GenericPublicKey {
-        self.public_dh_key.as_ref().unwrap_or_else(|| <super::securemessage::GenericPublicKey as ::protobuf::Message>::default_instance())
-    }
-    pub fn clear_public_dh_key(&mut self) {
-        self.public_dh_key.clear();
-    }
-
-    pub fn has_public_dh_key(&self) -> bool {
-        self.public_dh_key.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_public_dh_key(&mut self, v: super::securemessage::GenericPublicKey) {
-        self.public_dh_key = ::protobuf::SingularPtrField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_public_dh_key(&mut self) -> &mut super::securemessage::GenericPublicKey {
-        if self.public_dh_key.is_none() {
-            self.public_dh_key.set_default();
-        }
-        self.public_dh_key.as_mut().unwrap()
-    }
-
-    // Take field
-    pub fn take_public_dh_key(&mut self) -> super::securemessage::GenericPublicKey {
-        self.public_dh_key.take().unwrap_or_else(|| super::securemessage::GenericPublicKey::new())
-    }
-
     // optional int32 protocol_version = 2;
 
-
-    pub fn get_protocol_version(&self) -> i32 {
+    pub fn protocol_version(&self) -> i32 {
         self.protocol_version.unwrap_or(0i32)
     }
+
     pub fn clear_protocol_version(&mut self) {
         self.protocol_version = ::std::option::Option::None;
     }
@@ -292,6 +243,8 @@
 }
 
 impl ::protobuf::Message for InitiatorHello {
+    const NAME: &'static str = "InitiatorHello";
+
     fn is_initialized(&self) -> bool {
         for v in &self.public_dh_key {
             if !v.is_initialized() {
@@ -301,22 +254,17 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.public_dh_key)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    ::protobuf::rt::read_singular_message_into_field(is, &mut self.public_dh_key)?;
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.protocol_version = ::std::option::Option::Some(tmp);
+                16 => {
+                    self.protocol_version = ::std::option::Option::Some(is.read_int32()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -325,91 +273,70 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.public_dh_key.as_ref() {
+        if let Some(v) = self.public_dh_key.as_ref() {
             let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         }
         if let Some(v) = self.protocol_version {
-            my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(2, v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.public_dh_key.as_ref() {
-            os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.public_dh_key.as_ref() {
+            ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?;
         }
         if let Some(v) = self.protocol_version {
             os.write_int32(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> InitiatorHello {
         InitiatorHello::new()
     }
 
-    fn default_instance() -> &'static InitiatorHello {
-        static instance: ::protobuf::rt::LazyV2<InitiatorHello> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(InitiatorHello::new)
-    }
-}
-
-impl ::protobuf::Clear for InitiatorHello {
     fn clear(&mut self) {
         self.public_dh_key.clear();
         self.protocol_version = ::std::option::Option::None;
-        self.unknown_fields.clear();
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for InitiatorHello {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static InitiatorHello {
+        static instance: InitiatorHello = InitiatorHello {
+            public_dh_key: ::protobuf::MessageField::none(),
+            protocol_version: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.ResponderHello)
 pub struct ResponderHello {
     // message fields
-    pub public_dh_key: ::protobuf::SingularPtrField<super::securemessage::GenericPublicKey>,
-    protocol_version: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.ResponderHello.public_dh_key)
+    pub public_dh_key: ::protobuf::MessageField<super::securemessage::GenericPublicKey>,
+    // @@protoc_insertion_point(field:securegcm.ResponderHello.protocol_version)
+    pub protocol_version: ::std::option::Option<i32>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.ResponderHello.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a ResponderHello {
@@ -423,45 +350,12 @@
         ::std::default::Default::default()
     }
 
-    // optional .securemessage.GenericPublicKey public_dh_key = 1;
-
-
-    pub fn get_public_dh_key(&self) -> &super::securemessage::GenericPublicKey {
-        self.public_dh_key.as_ref().unwrap_or_else(|| <super::securemessage::GenericPublicKey as ::protobuf::Message>::default_instance())
-    }
-    pub fn clear_public_dh_key(&mut self) {
-        self.public_dh_key.clear();
-    }
-
-    pub fn has_public_dh_key(&self) -> bool {
-        self.public_dh_key.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_public_dh_key(&mut self, v: super::securemessage::GenericPublicKey) {
-        self.public_dh_key = ::protobuf::SingularPtrField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_public_dh_key(&mut self) -> &mut super::securemessage::GenericPublicKey {
-        if self.public_dh_key.is_none() {
-            self.public_dh_key.set_default();
-        }
-        self.public_dh_key.as_mut().unwrap()
-    }
-
-    // Take field
-    pub fn take_public_dh_key(&mut self) -> super::securemessage::GenericPublicKey {
-        self.public_dh_key.take().unwrap_or_else(|| super::securemessage::GenericPublicKey::new())
-    }
-
     // optional int32 protocol_version = 2;
 
-
-    pub fn get_protocol_version(&self) -> i32 {
+    pub fn protocol_version(&self) -> i32 {
         self.protocol_version.unwrap_or(0i32)
     }
+
     pub fn clear_protocol_version(&mut self) {
         self.protocol_version = ::std::option::Option::None;
     }
@@ -477,6 +371,8 @@
 }
 
 impl ::protobuf::Message for ResponderHello {
+    const NAME: &'static str = "ResponderHello";
+
     fn is_initialized(&self) -> bool {
         for v in &self.public_dh_key {
             if !v.is_initialized() {
@@ -486,22 +382,17 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.public_dh_key)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    ::protobuf::rt::read_singular_message_into_field(is, &mut self.public_dh_key)?;
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.protocol_version = ::std::option::Option::Some(tmp);
+                16 => {
+                    self.protocol_version = ::std::option::Option::Some(is.read_int32()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -510,92 +401,72 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.public_dh_key.as_ref() {
+        if let Some(v) = self.public_dh_key.as_ref() {
             let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         }
         if let Some(v) = self.protocol_version {
-            my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(2, v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.public_dh_key.as_ref() {
-            os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.public_dh_key.as_ref() {
+            ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?;
         }
         if let Some(v) = self.protocol_version {
             os.write_int32(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> ResponderHello {
         ResponderHello::new()
     }
 
-    fn default_instance() -> &'static ResponderHello {
-        static instance: ::protobuf::rt::LazyV2<ResponderHello> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(ResponderHello::new)
-    }
-}
-
-impl ::protobuf::Clear for ResponderHello {
     fn clear(&mut self) {
         self.public_dh_key.clear();
         self.protocol_version = ::std::option::Option::None;
-        self.unknown_fields.clear();
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for ResponderHello {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static ResponderHello {
+        static instance: ResponderHello = ResponderHello {
+            public_dh_key: ::protobuf::MessageField::none(),
+            protocol_version: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.EcPoint)
 pub struct EcPoint {
     // message fields
-    curve: ::std::option::Option<Curve>,
-    x: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    y: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.EcPoint.curve)
+    pub curve: ::std::option::Option<::protobuf::EnumOrUnknown<Curve>>,
+    // @@protoc_insertion_point(field:securegcm.EcPoint.x)
+    pub x: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.EcPoint.y)
+    pub y: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.EcPoint.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a EcPoint {
@@ -611,10 +482,13 @@
 
     // required .securegcm.Curve curve = 1;
 
-
-    pub fn get_curve(&self) -> Curve {
-        self.curve.unwrap_or(Curve::ED_25519)
+    pub fn curve(&self) -> Curve {
+        match self.curve {
+            Some(e) => e.enum_value_or(Curve::ED_25519),
+            None => Curve::ED_25519,
+        }
     }
+
     pub fn clear_curve(&mut self) {
         self.curve = ::std::option::Option::None;
     }
@@ -625,20 +499,20 @@
 
     // Param is passed by value, moved
     pub fn set_curve(&mut self, v: Curve) {
-        self.curve = ::std::option::Option::Some(v);
+        self.curve = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // required bytes x = 2;
 
-
-    pub fn get_x(&self) -> &[u8] {
+    pub fn x(&self) -> &[u8] {
         match self.x.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_x(&mut self) {
-        self.x.clear();
+        self.x = ::std::option::Option::None;
     }
 
     pub fn has_x(&self) -> bool {
@@ -647,14 +521,14 @@
 
     // Param is passed by value, moved
     pub fn set_x(&mut self, v: ::std::vec::Vec<u8>) {
-        self.x = ::protobuf::SingularField::some(v);
+        self.x = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_x(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.x.is_none() {
-            self.x.set_default();
+            self.x = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.x.as_mut().unwrap()
     }
@@ -666,15 +540,15 @@
 
     // required bytes y = 3;
 
-
-    pub fn get_y(&self) -> &[u8] {
+    pub fn y(&self) -> &[u8] {
         match self.y.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_y(&mut self) {
-        self.y.clear();
+        self.y = ::std::option::Option::None;
     }
 
     pub fn has_y(&self) -> bool {
@@ -683,14 +557,14 @@
 
     // Param is passed by value, moved
     pub fn set_y(&mut self, v: ::std::vec::Vec<u8>) {
-        self.y = ::protobuf::SingularField::some(v);
+        self.y = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_y(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.y.is_none() {
-            self.y.set_default();
+            self.y = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.y.as_mut().unwrap()
     }
@@ -702,6 +576,8 @@
 }
 
 impl ::protobuf::Message for EcPoint {
+    const NAME: &'static str = "EcPoint";
+
     fn is_initialized(&self) -> bool {
         if self.curve.is_none() {
             return false;
@@ -715,21 +591,20 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.curve, 1, &mut self.unknown_fields)?
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.curve = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.x)?;
+                18 => {
+                    self.x = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                3 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.y)?;
+                26 => {
+                    self.y = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -738,97 +613,81 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.curve {
-            my_size += ::protobuf::rt::enum_size(1, v);
+            my_size += ::protobuf::rt::int32_size(1, v.value());
         }
-        if let Some(ref v) = self.x.as_ref() {
+        if let Some(v) = self.x.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
-        if let Some(ref v) = self.y.as_ref() {
+        if let Some(v) = self.y.as_ref() {
             my_size += ::protobuf::rt::bytes_size(3, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.curve {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?;
+            os.write_enum(1, ::protobuf::EnumOrUnknown::value(&v))?;
         }
-        if let Some(ref v) = self.x.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.x.as_ref() {
+            os.write_bytes(2, v)?;
         }
-        if let Some(ref v) = self.y.as_ref() {
-            os.write_bytes(3, &v)?;
+        if let Some(v) = self.y.as_ref() {
+            os.write_bytes(3, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> EcPoint {
         EcPoint::new()
     }
 
-    fn default_instance() -> &'static EcPoint {
-        static instance: ::protobuf::rt::LazyV2<EcPoint> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(EcPoint::new)
-    }
-}
-
-impl ::protobuf::Clear for EcPoint {
     fn clear(&mut self) {
         self.curve = ::std::option::Option::None;
-        self.x.clear();
-        self.y.clear();
-        self.unknown_fields.clear();
+        self.x = ::std::option::Option::None;
+        self.y = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for EcPoint {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static EcPoint {
+        static instance: EcPoint = EcPoint {
+            curve: ::std::option::Option::None,
+            x: ::std::option::Option::None,
+            y: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.SpakeHandshakeMessage)
 pub struct SpakeHandshakeMessage {
     // message fields
-    flow_number: ::std::option::Option<i32>,
-    pub ec_point: ::protobuf::SingularPtrField<EcPoint>,
-    hash_value: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    payload: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.SpakeHandshakeMessage.flow_number)
+    pub flow_number: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.SpakeHandshakeMessage.ec_point)
+    pub ec_point: ::protobuf::MessageField<EcPoint>,
+    // @@protoc_insertion_point(field:securegcm.SpakeHandshakeMessage.hash_value)
+    pub hash_value: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.SpakeHandshakeMessage.payload)
+    pub payload: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.SpakeHandshakeMessage.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a SpakeHandshakeMessage {
@@ -844,10 +703,10 @@
 
     // optional int32 flow_number = 1;
 
-
-    pub fn get_flow_number(&self) -> i32 {
+    pub fn flow_number(&self) -> i32 {
         self.flow_number.unwrap_or(0)
     }
+
     pub fn clear_flow_number(&mut self) {
         self.flow_number = ::std::option::Option::None;
     }
@@ -861,50 +720,17 @@
         self.flow_number = ::std::option::Option::Some(v);
     }
 
-    // optional .securegcm.EcPoint ec_point = 2;
-
-
-    pub fn get_ec_point(&self) -> &EcPoint {
-        self.ec_point.as_ref().unwrap_or_else(|| <EcPoint as ::protobuf::Message>::default_instance())
-    }
-    pub fn clear_ec_point(&mut self) {
-        self.ec_point.clear();
-    }
-
-    pub fn has_ec_point(&self) -> bool {
-        self.ec_point.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_ec_point(&mut self, v: EcPoint) {
-        self.ec_point = ::protobuf::SingularPtrField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_ec_point(&mut self) -> &mut EcPoint {
-        if self.ec_point.is_none() {
-            self.ec_point.set_default();
-        }
-        self.ec_point.as_mut().unwrap()
-    }
-
-    // Take field
-    pub fn take_ec_point(&mut self) -> EcPoint {
-        self.ec_point.take().unwrap_or_else(|| EcPoint::new())
-    }
-
     // optional bytes hash_value = 3;
 
-
-    pub fn get_hash_value(&self) -> &[u8] {
+    pub fn hash_value(&self) -> &[u8] {
         match self.hash_value.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_hash_value(&mut self) {
-        self.hash_value.clear();
+        self.hash_value = ::std::option::Option::None;
     }
 
     pub fn has_hash_value(&self) -> bool {
@@ -913,14 +739,14 @@
 
     // Param is passed by value, moved
     pub fn set_hash_value(&mut self, v: ::std::vec::Vec<u8>) {
-        self.hash_value = ::protobuf::SingularField::some(v);
+        self.hash_value = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_hash_value(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.hash_value.is_none() {
-            self.hash_value.set_default();
+            self.hash_value = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.hash_value.as_mut().unwrap()
     }
@@ -932,15 +758,15 @@
 
     // optional bytes payload = 4;
 
-
-    pub fn get_payload(&self) -> &[u8] {
+    pub fn payload(&self) -> &[u8] {
         match self.payload.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_payload(&mut self) {
-        self.payload.clear();
+        self.payload = ::std::option::Option::None;
     }
 
     pub fn has_payload(&self) -> bool {
@@ -949,14 +775,14 @@
 
     // Param is passed by value, moved
     pub fn set_payload(&mut self, v: ::std::vec::Vec<u8>) {
-        self.payload = ::protobuf::SingularField::some(v);
+        self.payload = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_payload(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.payload.is_none() {
-            self.payload.set_default();
+            self.payload = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.payload.as_mut().unwrap()
     }
@@ -968,6 +794,8 @@
 }
 
 impl ::protobuf::Message for SpakeHandshakeMessage {
+    const NAME: &'static str = "SpakeHandshakeMessage";
+
     fn is_initialized(&self) -> bool {
         for v in &self.ec_point {
             if !v.is_initialized() {
@@ -977,28 +805,23 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.flow_number = ::std::option::Option::Some(tmp);
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.flow_number = ::std::option::Option::Some(is.read_int32()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.ec_point)?;
+                18 => {
+                    ::protobuf::rt::read_singular_message_into_field(is, &mut self.ec_point)?;
                 },
-                3 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.hash_value)?;
+                26 => {
+                    self.hash_value = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                4 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.payload)?;
+                34 => {
+                    self.payload = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1007,103 +830,85 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.flow_number {
-            my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(1, v);
         }
-        if let Some(ref v) = self.ec_point.as_ref() {
+        if let Some(v) = self.ec_point.as_ref() {
             let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         }
-        if let Some(ref v) = self.hash_value.as_ref() {
+        if let Some(v) = self.hash_value.as_ref() {
             my_size += ::protobuf::rt::bytes_size(3, &v);
         }
-        if let Some(ref v) = self.payload.as_ref() {
+        if let Some(v) = self.payload.as_ref() {
             my_size += ::protobuf::rt::bytes_size(4, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.flow_number {
             os.write_int32(1, v)?;
         }
-        if let Some(ref v) = self.ec_point.as_ref() {
-            os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+        if let Some(v) = self.ec_point.as_ref() {
+            ::protobuf::rt::write_message_field_with_cached_size(2, v, os)?;
         }
-        if let Some(ref v) = self.hash_value.as_ref() {
-            os.write_bytes(3, &v)?;
+        if let Some(v) = self.hash_value.as_ref() {
+            os.write_bytes(3, v)?;
         }
-        if let Some(ref v) = self.payload.as_ref() {
-            os.write_bytes(4, &v)?;
+        if let Some(v) = self.payload.as_ref() {
+            os.write_bytes(4, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> SpakeHandshakeMessage {
         SpakeHandshakeMessage::new()
     }
 
-    fn default_instance() -> &'static SpakeHandshakeMessage {
-        static instance: ::protobuf::rt::LazyV2<SpakeHandshakeMessage> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(SpakeHandshakeMessage::new)
-    }
-}
-
-impl ::protobuf::Clear for SpakeHandshakeMessage {
     fn clear(&mut self) {
         self.flow_number = ::std::option::Option::None;
         self.ec_point.clear();
-        self.hash_value.clear();
-        self.payload.clear();
-        self.unknown_fields.clear();
+        self.hash_value = ::std::option::Option::None;
+        self.payload = ::std::option::Option::None;
+        self.special_fields.clear();
+    }
+
+    fn default_instance() -> &'static SpakeHandshakeMessage {
+        static instance: SpakeHandshakeMessage = SpakeHandshakeMessage {
+            flow_number: ::std::option::Option::None,
+            ec_point: ::protobuf::MessageField::none(),
+            hash_value: ::std::option::Option::None,
+            payload: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for SpakeHandshakeMessage {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securegcm.Curve)
 pub enum Curve {
+    // @@protoc_insertion_point(enum_value:securegcm.Curve.ED_25519)
     ED_25519 = 1,
 }
 
-impl ::protobuf::ProtobufEnum for Curve {
+impl ::protobuf::Enum for Curve {
+    const NAME: &'static str = "Curve";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -1115,15 +920,9 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [Curve] = &[
-            Curve::ED_25519,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for Curve {
+    const VALUES: &'static [Curve] = &[
+        Curve::ED_25519,
+    ];
 }
 
 // Note, `Default` is implemented although default value is not 0
@@ -1133,8 +932,3 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for Curve {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs
index 8a908b1..3231440 100644
--- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs
+++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs
@@ -12,7 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// This file is generated by rust-protobuf 2.28.0. Do not edit
+// This file is generated by rust-protobuf 3.2.0. Do not edit
+// .proto file is parsed by protoc 3.19.1
 // @generated
 
 // https://github.com/rust-lang/rust-clippy/issues/702
@@ -29,58 +30,99 @@
 #![allow(non_snake_case)]
 #![allow(non_upper_case_globals)]
 #![allow(trivial_casts)]
-#![allow(unused_imports)]
 #![allow(unused_results)]
+#![allow(unused_mut)]
+
 //! Generated file from `securegcm.proto`
+// Generated for lite runtime
 
 /// Generated files are compatible only with the same version
 /// of protobuf runtime.
-// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_28_0;
+const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.GcmDeviceInfo)
 pub struct GcmDeviceInfo {
     // message fields
-    android_device_id: ::std::option::Option<u64>,
-    gcm_registration_id: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    apn_registration_id: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    notification_enabled: ::std::option::Option<bool>,
-    bluetooth_mac_address: ::protobuf::SingularField<::std::string::String>,
-    device_master_key_hash: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    user_public_key: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    device_model: ::protobuf::SingularField<::std::string::String>,
-    locale: ::protobuf::SingularField<::std::string::String>,
-    key_handle: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    counter: ::std::option::Option<i64>,
-    device_os_version: ::protobuf::SingularField<::std::string::String>,
-    device_os_version_code: ::std::option::Option<i64>,
-    device_os_release: ::protobuf::SingularField<::std::string::String>,
-    device_os_codename: ::protobuf::SingularField<::std::string::String>,
-    device_software_version: ::protobuf::SingularField<::std::string::String>,
-    device_software_version_code: ::std::option::Option<i64>,
-    device_software_package: ::protobuf::SingularField<::std::string::String>,
-    device_display_diagonal_mils: ::std::option::Option<i32>,
-    device_authzen_version: ::std::option::Option<i32>,
-    long_device_id: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    device_manufacturer: ::protobuf::SingularField<::std::string::String>,
-    device_type: ::std::option::Option<DeviceType>,
-    using_secure_screenlock: ::std::option::Option<bool>,
-    auto_unlock_screenlock_supported: ::std::option::Option<bool>,
-    auto_unlock_screenlock_enabled: ::std::option::Option<bool>,
-    bluetooth_radio_supported: ::std::option::Option<bool>,
-    bluetooth_radio_enabled: ::std::option::Option<bool>,
-    mobile_data_supported: ::std::option::Option<bool>,
-    tethering_supported: ::std::option::Option<bool>,
-    ble_radio_supported: ::std::option::Option<bool>,
-    pixel_experience: ::std::option::Option<bool>,
-    arc_plus_plus: ::std::option::Option<bool>,
-    is_screenlock_state_flaky: ::std::option::Option<bool>,
-    pub supported_software_features: ::std::vec::Vec<SoftwareFeature>,
-    pub enabled_software_features: ::std::vec::Vec<SoftwareFeature>,
-    enrollment_session_id: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    oauth_token: ::protobuf::SingularField<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.android_device_id)
+    pub android_device_id: ::std::option::Option<u64>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.gcm_registration_id)
+    pub gcm_registration_id: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.apn_registration_id)
+    pub apn_registration_id: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.notification_enabled)
+    pub notification_enabled: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.bluetooth_mac_address)
+    pub bluetooth_mac_address: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_master_key_hash)
+    pub device_master_key_hash: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.user_public_key)
+    pub user_public_key: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_model)
+    pub device_model: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.locale)
+    pub locale: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.key_handle)
+    pub key_handle: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.counter)
+    pub counter: ::std::option::Option<i64>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_version)
+    pub device_os_version: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_version_code)
+    pub device_os_version_code: ::std::option::Option<i64>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_release)
+    pub device_os_release: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_codename)
+    pub device_os_codename: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_software_version)
+    pub device_software_version: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_software_version_code)
+    pub device_software_version_code: ::std::option::Option<i64>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_software_package)
+    pub device_software_package: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_display_diagonal_mils)
+    pub device_display_diagonal_mils: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_authzen_version)
+    pub device_authzen_version: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.long_device_id)
+    pub long_device_id: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_manufacturer)
+    pub device_manufacturer: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_type)
+    pub device_type: ::std::option::Option<::protobuf::EnumOrUnknown<DeviceType>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.using_secure_screenlock)
+    pub using_secure_screenlock: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.auto_unlock_screenlock_supported)
+    pub auto_unlock_screenlock_supported: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.auto_unlock_screenlock_enabled)
+    pub auto_unlock_screenlock_enabled: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.bluetooth_radio_supported)
+    pub bluetooth_radio_supported: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.bluetooth_radio_enabled)
+    pub bluetooth_radio_enabled: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.mobile_data_supported)
+    pub mobile_data_supported: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.tethering_supported)
+    pub tethering_supported: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.ble_radio_supported)
+    pub ble_radio_supported: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.pixel_experience)
+    pub pixel_experience: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.arc_plus_plus)
+    pub arc_plus_plus: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.is_screenlock_state_flaky)
+    pub is_screenlock_state_flaky: ::std::option::Option<bool>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.supported_software_features)
+    pub supported_software_features: ::std::vec::Vec<::protobuf::EnumOrUnknown<SoftwareFeature>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.enabled_software_features)
+    pub enabled_software_features: ::std::vec::Vec<::protobuf::EnumOrUnknown<SoftwareFeature>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.enrollment_session_id)
+    pub enrollment_session_id: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.oauth_token)
+    pub oauth_token: ::std::option::Option<::std::string::String>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.GcmDeviceInfo.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a GcmDeviceInfo {
@@ -96,10 +138,10 @@
 
     // optional fixed64 android_device_id = 1;
 
-
-    pub fn get_android_device_id(&self) -> u64 {
+    pub fn android_device_id(&self) -> u64 {
         self.android_device_id.unwrap_or(0)
     }
+
     pub fn clear_android_device_id(&mut self) {
         self.android_device_id = ::std::option::Option::None;
     }
@@ -115,15 +157,15 @@
 
     // optional bytes gcm_registration_id = 102;
 
-
-    pub fn get_gcm_registration_id(&self) -> &[u8] {
+    pub fn gcm_registration_id(&self) -> &[u8] {
         match self.gcm_registration_id.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_gcm_registration_id(&mut self) {
-        self.gcm_registration_id.clear();
+        self.gcm_registration_id = ::std::option::Option::None;
     }
 
     pub fn has_gcm_registration_id(&self) -> bool {
@@ -132,14 +174,14 @@
 
     // Param is passed by value, moved
     pub fn set_gcm_registration_id(&mut self, v: ::std::vec::Vec<u8>) {
-        self.gcm_registration_id = ::protobuf::SingularField::some(v);
+        self.gcm_registration_id = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_gcm_registration_id(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.gcm_registration_id.is_none() {
-            self.gcm_registration_id.set_default();
+            self.gcm_registration_id = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.gcm_registration_id.as_mut().unwrap()
     }
@@ -151,15 +193,15 @@
 
     // optional bytes apn_registration_id = 202;
 
-
-    pub fn get_apn_registration_id(&self) -> &[u8] {
+    pub fn apn_registration_id(&self) -> &[u8] {
         match self.apn_registration_id.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_apn_registration_id(&mut self) {
-        self.apn_registration_id.clear();
+        self.apn_registration_id = ::std::option::Option::None;
     }
 
     pub fn has_apn_registration_id(&self) -> bool {
@@ -168,14 +210,14 @@
 
     // Param is passed by value, moved
     pub fn set_apn_registration_id(&mut self, v: ::std::vec::Vec<u8>) {
-        self.apn_registration_id = ::protobuf::SingularField::some(v);
+        self.apn_registration_id = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_apn_registration_id(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.apn_registration_id.is_none() {
-            self.apn_registration_id.set_default();
+            self.apn_registration_id = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.apn_registration_id.as_mut().unwrap()
     }
@@ -187,10 +229,10 @@
 
     // optional bool notification_enabled = 203;
 
-
-    pub fn get_notification_enabled(&self) -> bool {
+    pub fn notification_enabled(&self) -> bool {
         self.notification_enabled.unwrap_or(true)
     }
+
     pub fn clear_notification_enabled(&mut self) {
         self.notification_enabled = ::std::option::Option::None;
     }
@@ -206,15 +248,15 @@
 
     // optional string bluetooth_mac_address = 302;
 
-
-    pub fn get_bluetooth_mac_address(&self) -> &str {
+    pub fn bluetooth_mac_address(&self) -> &str {
         match self.bluetooth_mac_address.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_bluetooth_mac_address(&mut self) {
-        self.bluetooth_mac_address.clear();
+        self.bluetooth_mac_address = ::std::option::Option::None;
     }
 
     pub fn has_bluetooth_mac_address(&self) -> bool {
@@ -223,14 +265,14 @@
 
     // Param is passed by value, moved
     pub fn set_bluetooth_mac_address(&mut self, v: ::std::string::String) {
-        self.bluetooth_mac_address = ::protobuf::SingularField::some(v);
+        self.bluetooth_mac_address = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_bluetooth_mac_address(&mut self) -> &mut ::std::string::String {
         if self.bluetooth_mac_address.is_none() {
-            self.bluetooth_mac_address.set_default();
+            self.bluetooth_mac_address = ::std::option::Option::Some(::std::string::String::new());
         }
         self.bluetooth_mac_address.as_mut().unwrap()
     }
@@ -242,15 +284,15 @@
 
     // optional bytes device_master_key_hash = 103;
 
-
-    pub fn get_device_master_key_hash(&self) -> &[u8] {
+    pub fn device_master_key_hash(&self) -> &[u8] {
         match self.device_master_key_hash.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_device_master_key_hash(&mut self) {
-        self.device_master_key_hash.clear();
+        self.device_master_key_hash = ::std::option::Option::None;
     }
 
     pub fn has_device_master_key_hash(&self) -> bool {
@@ -259,14 +301,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_master_key_hash(&mut self, v: ::std::vec::Vec<u8>) {
-        self.device_master_key_hash = ::protobuf::SingularField::some(v);
+        self.device_master_key_hash = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_master_key_hash(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.device_master_key_hash.is_none() {
-            self.device_master_key_hash.set_default();
+            self.device_master_key_hash = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.device_master_key_hash.as_mut().unwrap()
     }
@@ -278,15 +320,15 @@
 
     // required bytes user_public_key = 4;
 
-
-    pub fn get_user_public_key(&self) -> &[u8] {
+    pub fn user_public_key(&self) -> &[u8] {
         match self.user_public_key.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_user_public_key(&mut self) {
-        self.user_public_key.clear();
+        self.user_public_key = ::std::option::Option::None;
     }
 
     pub fn has_user_public_key(&self) -> bool {
@@ -295,14 +337,14 @@
 
     // Param is passed by value, moved
     pub fn set_user_public_key(&mut self, v: ::std::vec::Vec<u8>) {
-        self.user_public_key = ::protobuf::SingularField::some(v);
+        self.user_public_key = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_user_public_key(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.user_public_key.is_none() {
-            self.user_public_key.set_default();
+            self.user_public_key = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.user_public_key.as_mut().unwrap()
     }
@@ -314,15 +356,15 @@
 
     // optional string device_model = 7;
 
-
-    pub fn get_device_model(&self) -> &str {
+    pub fn device_model(&self) -> &str {
         match self.device_model.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_device_model(&mut self) {
-        self.device_model.clear();
+        self.device_model = ::std::option::Option::None;
     }
 
     pub fn has_device_model(&self) -> bool {
@@ -331,14 +373,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_model(&mut self, v: ::std::string::String) {
-        self.device_model = ::protobuf::SingularField::some(v);
+        self.device_model = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_model(&mut self) -> &mut ::std::string::String {
         if self.device_model.is_none() {
-            self.device_model.set_default();
+            self.device_model = ::std::option::Option::Some(::std::string::String::new());
         }
         self.device_model.as_mut().unwrap()
     }
@@ -350,15 +392,15 @@
 
     // optional string locale = 8;
 
-
-    pub fn get_locale(&self) -> &str {
+    pub fn locale(&self) -> &str {
         match self.locale.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_locale(&mut self) {
-        self.locale.clear();
+        self.locale = ::std::option::Option::None;
     }
 
     pub fn has_locale(&self) -> bool {
@@ -367,14 +409,14 @@
 
     // Param is passed by value, moved
     pub fn set_locale(&mut self, v: ::std::string::String) {
-        self.locale = ::protobuf::SingularField::some(v);
+        self.locale = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_locale(&mut self) -> &mut ::std::string::String {
         if self.locale.is_none() {
-            self.locale.set_default();
+            self.locale = ::std::option::Option::Some(::std::string::String::new());
         }
         self.locale.as_mut().unwrap()
     }
@@ -386,15 +428,15 @@
 
     // optional bytes key_handle = 9;
 
-
-    pub fn get_key_handle(&self) -> &[u8] {
+    pub fn key_handle(&self) -> &[u8] {
         match self.key_handle.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_key_handle(&mut self) {
-        self.key_handle.clear();
+        self.key_handle = ::std::option::Option::None;
     }
 
     pub fn has_key_handle(&self) -> bool {
@@ -403,14 +445,14 @@
 
     // Param is passed by value, moved
     pub fn set_key_handle(&mut self, v: ::std::vec::Vec<u8>) {
-        self.key_handle = ::protobuf::SingularField::some(v);
+        self.key_handle = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_key_handle(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.key_handle.is_none() {
-            self.key_handle.set_default();
+            self.key_handle = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.key_handle.as_mut().unwrap()
     }
@@ -422,10 +464,10 @@
 
     // optional int64 counter = 12;
 
-
-    pub fn get_counter(&self) -> i64 {
+    pub fn counter(&self) -> i64 {
         self.counter.unwrap_or(0i64)
     }
+
     pub fn clear_counter(&mut self) {
         self.counter = ::std::option::Option::None;
     }
@@ -441,15 +483,15 @@
 
     // optional string device_os_version = 13;
 
-
-    pub fn get_device_os_version(&self) -> &str {
+    pub fn device_os_version(&self) -> &str {
         match self.device_os_version.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_device_os_version(&mut self) {
-        self.device_os_version.clear();
+        self.device_os_version = ::std::option::Option::None;
     }
 
     pub fn has_device_os_version(&self) -> bool {
@@ -458,14 +500,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_os_version(&mut self, v: ::std::string::String) {
-        self.device_os_version = ::protobuf::SingularField::some(v);
+        self.device_os_version = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_os_version(&mut self) -> &mut ::std::string::String {
         if self.device_os_version.is_none() {
-            self.device_os_version.set_default();
+            self.device_os_version = ::std::option::Option::Some(::std::string::String::new());
         }
         self.device_os_version.as_mut().unwrap()
     }
@@ -477,10 +519,10 @@
 
     // optional int64 device_os_version_code = 14;
 
-
-    pub fn get_device_os_version_code(&self) -> i64 {
+    pub fn device_os_version_code(&self) -> i64 {
         self.device_os_version_code.unwrap_or(0)
     }
+
     pub fn clear_device_os_version_code(&mut self) {
         self.device_os_version_code = ::std::option::Option::None;
     }
@@ -496,15 +538,15 @@
 
     // optional string device_os_release = 15;
 
-
-    pub fn get_device_os_release(&self) -> &str {
+    pub fn device_os_release(&self) -> &str {
         match self.device_os_release.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_device_os_release(&mut self) {
-        self.device_os_release.clear();
+        self.device_os_release = ::std::option::Option::None;
     }
 
     pub fn has_device_os_release(&self) -> bool {
@@ -513,14 +555,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_os_release(&mut self, v: ::std::string::String) {
-        self.device_os_release = ::protobuf::SingularField::some(v);
+        self.device_os_release = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_os_release(&mut self) -> &mut ::std::string::String {
         if self.device_os_release.is_none() {
-            self.device_os_release.set_default();
+            self.device_os_release = ::std::option::Option::Some(::std::string::String::new());
         }
         self.device_os_release.as_mut().unwrap()
     }
@@ -532,15 +574,15 @@
 
     // optional string device_os_codename = 16;
 
-
-    pub fn get_device_os_codename(&self) -> &str {
+    pub fn device_os_codename(&self) -> &str {
         match self.device_os_codename.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_device_os_codename(&mut self) {
-        self.device_os_codename.clear();
+        self.device_os_codename = ::std::option::Option::None;
     }
 
     pub fn has_device_os_codename(&self) -> bool {
@@ -549,14 +591,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_os_codename(&mut self, v: ::std::string::String) {
-        self.device_os_codename = ::protobuf::SingularField::some(v);
+        self.device_os_codename = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_os_codename(&mut self) -> &mut ::std::string::String {
         if self.device_os_codename.is_none() {
-            self.device_os_codename.set_default();
+            self.device_os_codename = ::std::option::Option::Some(::std::string::String::new());
         }
         self.device_os_codename.as_mut().unwrap()
     }
@@ -568,15 +610,15 @@
 
     // optional string device_software_version = 17;
 
-
-    pub fn get_device_software_version(&self) -> &str {
+    pub fn device_software_version(&self) -> &str {
         match self.device_software_version.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_device_software_version(&mut self) {
-        self.device_software_version.clear();
+        self.device_software_version = ::std::option::Option::None;
     }
 
     pub fn has_device_software_version(&self) -> bool {
@@ -585,14 +627,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_software_version(&mut self, v: ::std::string::String) {
-        self.device_software_version = ::protobuf::SingularField::some(v);
+        self.device_software_version = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_software_version(&mut self) -> &mut ::std::string::String {
         if self.device_software_version.is_none() {
-            self.device_software_version.set_default();
+            self.device_software_version = ::std::option::Option::Some(::std::string::String::new());
         }
         self.device_software_version.as_mut().unwrap()
     }
@@ -604,10 +646,10 @@
 
     // optional int64 device_software_version_code = 18;
 
-
-    pub fn get_device_software_version_code(&self) -> i64 {
+    pub fn device_software_version_code(&self) -> i64 {
         self.device_software_version_code.unwrap_or(0)
     }
+
     pub fn clear_device_software_version_code(&mut self) {
         self.device_software_version_code = ::std::option::Option::None;
     }
@@ -623,15 +665,15 @@
 
     // optional string device_software_package = 19;
 
-
-    pub fn get_device_software_package(&self) -> &str {
+    pub fn device_software_package(&self) -> &str {
         match self.device_software_package.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_device_software_package(&mut self) {
-        self.device_software_package.clear();
+        self.device_software_package = ::std::option::Option::None;
     }
 
     pub fn has_device_software_package(&self) -> bool {
@@ -640,14 +682,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_software_package(&mut self, v: ::std::string::String) {
-        self.device_software_package = ::protobuf::SingularField::some(v);
+        self.device_software_package = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_software_package(&mut self) -> &mut ::std::string::String {
         if self.device_software_package.is_none() {
-            self.device_software_package.set_default();
+            self.device_software_package = ::std::option::Option::Some(::std::string::String::new());
         }
         self.device_software_package.as_mut().unwrap()
     }
@@ -659,10 +701,10 @@
 
     // optional int32 device_display_diagonal_mils = 22;
 
-
-    pub fn get_device_display_diagonal_mils(&self) -> i32 {
+    pub fn device_display_diagonal_mils(&self) -> i32 {
         self.device_display_diagonal_mils.unwrap_or(0)
     }
+
     pub fn clear_device_display_diagonal_mils(&mut self) {
         self.device_display_diagonal_mils = ::std::option::Option::None;
     }
@@ -678,10 +720,10 @@
 
     // optional int32 device_authzen_version = 24;
 
-
-    pub fn get_device_authzen_version(&self) -> i32 {
+    pub fn device_authzen_version(&self) -> i32 {
         self.device_authzen_version.unwrap_or(0)
     }
+
     pub fn clear_device_authzen_version(&mut self) {
         self.device_authzen_version = ::std::option::Option::None;
     }
@@ -697,15 +739,15 @@
 
     // optional bytes long_device_id = 29;
 
-
-    pub fn get_long_device_id(&self) -> &[u8] {
+    pub fn long_device_id(&self) -> &[u8] {
         match self.long_device_id.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_long_device_id(&mut self) {
-        self.long_device_id.clear();
+        self.long_device_id = ::std::option::Option::None;
     }
 
     pub fn has_long_device_id(&self) -> bool {
@@ -714,14 +756,14 @@
 
     // Param is passed by value, moved
     pub fn set_long_device_id(&mut self, v: ::std::vec::Vec<u8>) {
-        self.long_device_id = ::protobuf::SingularField::some(v);
+        self.long_device_id = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_long_device_id(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.long_device_id.is_none() {
-            self.long_device_id.set_default();
+            self.long_device_id = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.long_device_id.as_mut().unwrap()
     }
@@ -733,15 +775,15 @@
 
     // optional string device_manufacturer = 31;
 
-
-    pub fn get_device_manufacturer(&self) -> &str {
+    pub fn device_manufacturer(&self) -> &str {
         match self.device_manufacturer.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_device_manufacturer(&mut self) {
-        self.device_manufacturer.clear();
+        self.device_manufacturer = ::std::option::Option::None;
     }
 
     pub fn has_device_manufacturer(&self) -> bool {
@@ -750,14 +792,14 @@
 
     // Param is passed by value, moved
     pub fn set_device_manufacturer(&mut self, v: ::std::string::String) {
-        self.device_manufacturer = ::protobuf::SingularField::some(v);
+        self.device_manufacturer = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_device_manufacturer(&mut self) -> &mut ::std::string::String {
         if self.device_manufacturer.is_none() {
-            self.device_manufacturer.set_default();
+            self.device_manufacturer = ::std::option::Option::Some(::std::string::String::new());
         }
         self.device_manufacturer.as_mut().unwrap()
     }
@@ -769,10 +811,13 @@
 
     // optional .securegcm.DeviceType device_type = 32;
 
-
-    pub fn get_device_type(&self) -> DeviceType {
-        self.device_type.unwrap_or(DeviceType::ANDROID)
+    pub fn device_type(&self) -> DeviceType {
+        match self.device_type {
+            Some(e) => e.enum_value_or(DeviceType::ANDROID),
+            None => DeviceType::ANDROID,
+        }
     }
+
     pub fn clear_device_type(&mut self) {
         self.device_type = ::std::option::Option::None;
     }
@@ -783,15 +828,15 @@
 
     // Param is passed by value, moved
     pub fn set_device_type(&mut self, v: DeviceType) {
-        self.device_type = ::std::option::Option::Some(v);
+        self.device_type = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // optional bool using_secure_screenlock = 400;
 
-
-    pub fn get_using_secure_screenlock(&self) -> bool {
+    pub fn using_secure_screenlock(&self) -> bool {
         self.using_secure_screenlock.unwrap_or(false)
     }
+
     pub fn clear_using_secure_screenlock(&mut self) {
         self.using_secure_screenlock = ::std::option::Option::None;
     }
@@ -807,10 +852,10 @@
 
     // optional bool auto_unlock_screenlock_supported = 401;
 
-
-    pub fn get_auto_unlock_screenlock_supported(&self) -> bool {
+    pub fn auto_unlock_screenlock_supported(&self) -> bool {
         self.auto_unlock_screenlock_supported.unwrap_or(false)
     }
+
     pub fn clear_auto_unlock_screenlock_supported(&mut self) {
         self.auto_unlock_screenlock_supported = ::std::option::Option::None;
     }
@@ -826,10 +871,10 @@
 
     // optional bool auto_unlock_screenlock_enabled = 402;
 
-
-    pub fn get_auto_unlock_screenlock_enabled(&self) -> bool {
+    pub fn auto_unlock_screenlock_enabled(&self) -> bool {
         self.auto_unlock_screenlock_enabled.unwrap_or(false)
     }
+
     pub fn clear_auto_unlock_screenlock_enabled(&mut self) {
         self.auto_unlock_screenlock_enabled = ::std::option::Option::None;
     }
@@ -845,10 +890,10 @@
 
     // optional bool bluetooth_radio_supported = 403;
 
-
-    pub fn get_bluetooth_radio_supported(&self) -> bool {
+    pub fn bluetooth_radio_supported(&self) -> bool {
         self.bluetooth_radio_supported.unwrap_or(false)
     }
+
     pub fn clear_bluetooth_radio_supported(&mut self) {
         self.bluetooth_radio_supported = ::std::option::Option::None;
     }
@@ -864,10 +909,10 @@
 
     // optional bool bluetooth_radio_enabled = 404;
 
-
-    pub fn get_bluetooth_radio_enabled(&self) -> bool {
+    pub fn bluetooth_radio_enabled(&self) -> bool {
         self.bluetooth_radio_enabled.unwrap_or(false)
     }
+
     pub fn clear_bluetooth_radio_enabled(&mut self) {
         self.bluetooth_radio_enabled = ::std::option::Option::None;
     }
@@ -883,10 +928,10 @@
 
     // optional bool mobile_data_supported = 405;
 
-
-    pub fn get_mobile_data_supported(&self) -> bool {
+    pub fn mobile_data_supported(&self) -> bool {
         self.mobile_data_supported.unwrap_or(false)
     }
+
     pub fn clear_mobile_data_supported(&mut self) {
         self.mobile_data_supported = ::std::option::Option::None;
     }
@@ -902,10 +947,10 @@
 
     // optional bool tethering_supported = 406;
 
-
-    pub fn get_tethering_supported(&self) -> bool {
+    pub fn tethering_supported(&self) -> bool {
         self.tethering_supported.unwrap_or(false)
     }
+
     pub fn clear_tethering_supported(&mut self) {
         self.tethering_supported = ::std::option::Option::None;
     }
@@ -921,10 +966,10 @@
 
     // optional bool ble_radio_supported = 407;
 
-
-    pub fn get_ble_radio_supported(&self) -> bool {
+    pub fn ble_radio_supported(&self) -> bool {
         self.ble_radio_supported.unwrap_or(false)
     }
+
     pub fn clear_ble_radio_supported(&mut self) {
         self.ble_radio_supported = ::std::option::Option::None;
     }
@@ -940,10 +985,10 @@
 
     // optional bool pixel_experience = 408;
 
-
-    pub fn get_pixel_experience(&self) -> bool {
+    pub fn pixel_experience(&self) -> bool {
         self.pixel_experience.unwrap_or(false)
     }
+
     pub fn clear_pixel_experience(&mut self) {
         self.pixel_experience = ::std::option::Option::None;
     }
@@ -959,10 +1004,10 @@
 
     // optional bool arc_plus_plus = 409;
 
-
-    pub fn get_arc_plus_plus(&self) -> bool {
+    pub fn arc_plus_plus(&self) -> bool {
         self.arc_plus_plus.unwrap_or(false)
     }
+
     pub fn clear_arc_plus_plus(&mut self) {
         self.arc_plus_plus = ::std::option::Option::None;
     }
@@ -978,10 +1023,10 @@
 
     // optional bool is_screenlock_state_flaky = 410;
 
-
-    pub fn get_is_screenlock_state_flaky(&self) -> bool {
+    pub fn is_screenlock_state_flaky(&self) -> bool {
         self.is_screenlock_state_flaky.unwrap_or(false)
     }
+
     pub fn clear_is_screenlock_state_flaky(&mut self) {
         self.is_screenlock_state_flaky = ::std::option::Option::None;
     }
@@ -995,67 +1040,17 @@
         self.is_screenlock_state_flaky = ::std::option::Option::Some(v);
     }
 
-    // repeated .securegcm.SoftwareFeature supported_software_features = 411;
-
-
-    pub fn get_supported_software_features(&self) -> &[SoftwareFeature] {
-        &self.supported_software_features
-    }
-    pub fn clear_supported_software_features(&mut self) {
-        self.supported_software_features.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_supported_software_features(&mut self, v: ::std::vec::Vec<SoftwareFeature>) {
-        self.supported_software_features = v;
-    }
-
-    // Mutable pointer to the field.
-    pub fn mut_supported_software_features(&mut self) -> &mut ::std::vec::Vec<SoftwareFeature> {
-        &mut self.supported_software_features
-    }
-
-    // Take field
-    pub fn take_supported_software_features(&mut self) -> ::std::vec::Vec<SoftwareFeature> {
-        ::std::mem::replace(&mut self.supported_software_features, ::std::vec::Vec::new())
-    }
-
-    // repeated .securegcm.SoftwareFeature enabled_software_features = 412;
-
-
-    pub fn get_enabled_software_features(&self) -> &[SoftwareFeature] {
-        &self.enabled_software_features
-    }
-    pub fn clear_enabled_software_features(&mut self) {
-        self.enabled_software_features.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_enabled_software_features(&mut self, v: ::std::vec::Vec<SoftwareFeature>) {
-        self.enabled_software_features = v;
-    }
-
-    // Mutable pointer to the field.
-    pub fn mut_enabled_software_features(&mut self) -> &mut ::std::vec::Vec<SoftwareFeature> {
-        &mut self.enabled_software_features
-    }
-
-    // Take field
-    pub fn take_enabled_software_features(&mut self) -> ::std::vec::Vec<SoftwareFeature> {
-        ::std::mem::replace(&mut self.enabled_software_features, ::std::vec::Vec::new())
-    }
-
     // optional bytes enrollment_session_id = 1000;
 
-
-    pub fn get_enrollment_session_id(&self) -> &[u8] {
+    pub fn enrollment_session_id(&self) -> &[u8] {
         match self.enrollment_session_id.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_enrollment_session_id(&mut self) {
-        self.enrollment_session_id.clear();
+        self.enrollment_session_id = ::std::option::Option::None;
     }
 
     pub fn has_enrollment_session_id(&self) -> bool {
@@ -1064,14 +1059,14 @@
 
     // Param is passed by value, moved
     pub fn set_enrollment_session_id(&mut self, v: ::std::vec::Vec<u8>) {
-        self.enrollment_session_id = ::protobuf::SingularField::some(v);
+        self.enrollment_session_id = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_enrollment_session_id(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.enrollment_session_id.is_none() {
-            self.enrollment_session_id.set_default();
+            self.enrollment_session_id = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.enrollment_session_id.as_mut().unwrap()
     }
@@ -1083,15 +1078,15 @@
 
     // optional string oauth_token = 1001;
 
-
-    pub fn get_oauth_token(&self) -> &str {
+    pub fn oauth_token(&self) -> &str {
         match self.oauth_token.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_oauth_token(&mut self) {
-        self.oauth_token.clear();
+        self.oauth_token = ::std::option::Option::None;
     }
 
     pub fn has_oauth_token(&self) -> bool {
@@ -1100,14 +1095,14 @@
 
     // Param is passed by value, moved
     pub fn set_oauth_token(&mut self, v: ::std::string::String) {
-        self.oauth_token = ::protobuf::SingularField::some(v);
+        self.oauth_token = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_oauth_token(&mut self) -> &mut ::std::string::String {
         if self.oauth_token.is_none() {
-            self.oauth_token.set_default();
+            self.oauth_token = ::std::option::Option::Some(::std::string::String::new());
         }
         self.oauth_token.as_mut().unwrap()
     }
@@ -1119,6 +1114,8 @@
 }
 
 impl ::protobuf::Message for GcmDeviceInfo {
+    const NAME: &'static str = "GcmDeviceInfo";
+
     fn is_initialized(&self) -> bool {
         if self.user_public_key.is_none() {
             return false;
@@ -1126,198 +1123,131 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeFixed64 {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_fixed64()?;
-                    self.android_device_id = ::std::option::Option::Some(tmp);
-                },
-                102 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.gcm_registration_id)?;
-                },
-                202 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.apn_registration_id)?;
-                },
-                203 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.notification_enabled = ::std::option::Option::Some(tmp);
-                },
-                302 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.bluetooth_mac_address)?;
-                },
-                103 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.device_master_key_hash)?;
-                },
-                4 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.user_public_key)?;
-                },
-                7 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.device_model)?;
-                },
-                8 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.locale)?;
-                },
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
                 9 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.key_handle)?;
+                    self.android_device_id = ::std::option::Option::Some(is.read_fixed64()?);
                 },
-                12 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int64()?;
-                    self.counter = ::std::option::Option::Some(tmp);
+                818 => {
+                    self.gcm_registration_id = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                13 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.device_os_version)?;
+                1618 => {
+                    self.apn_registration_id = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                14 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int64()?;
-                    self.device_os_version_code = ::std::option::Option::Some(tmp);
+                1624 => {
+                    self.notification_enabled = ::std::option::Option::Some(is.read_bool()?);
                 },
-                15 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.device_os_release)?;
+                2418 => {
+                    self.bluetooth_mac_address = ::std::option::Option::Some(is.read_string()?);
                 },
-                16 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.device_os_codename)?;
+                826 => {
+                    self.device_master_key_hash = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                17 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.device_software_version)?;
+                34 => {
+                    self.user_public_key = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                18 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int64()?;
-                    self.device_software_version_code = ::std::option::Option::Some(tmp);
+                58 => {
+                    self.device_model = ::std::option::Option::Some(is.read_string()?);
                 },
-                19 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.device_software_package)?;
+                66 => {
+                    self.locale = ::std::option::Option::Some(is.read_string()?);
                 },
-                22 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.device_display_diagonal_mils = ::std::option::Option::Some(tmp);
+                74 => {
+                    self.key_handle = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                24 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.device_authzen_version = ::std::option::Option::Some(tmp);
+                96 => {
+                    self.counter = ::std::option::Option::Some(is.read_int64()?);
                 },
-                29 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.long_device_id)?;
+                106 => {
+                    self.device_os_version = ::std::option::Option::Some(is.read_string()?);
                 },
-                31 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.device_manufacturer)?;
+                112 => {
+                    self.device_os_version_code = ::std::option::Option::Some(is.read_int64()?);
                 },
-                32 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.device_type, 32, &mut self.unknown_fields)?
+                122 => {
+                    self.device_os_release = ::std::option::Option::Some(is.read_string()?);
                 },
-                400 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.using_secure_screenlock = ::std::option::Option::Some(tmp);
+                130 => {
+                    self.device_os_codename = ::std::option::Option::Some(is.read_string()?);
                 },
-                401 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.auto_unlock_screenlock_supported = ::std::option::Option::Some(tmp);
+                138 => {
+                    self.device_software_version = ::std::option::Option::Some(is.read_string()?);
                 },
-                402 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.auto_unlock_screenlock_enabled = ::std::option::Option::Some(tmp);
+                144 => {
+                    self.device_software_version_code = ::std::option::Option::Some(is.read_int64()?);
                 },
-                403 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.bluetooth_radio_supported = ::std::option::Option::Some(tmp);
+                154 => {
+                    self.device_software_package = ::std::option::Option::Some(is.read_string()?);
                 },
-                404 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.bluetooth_radio_enabled = ::std::option::Option::Some(tmp);
+                176 => {
+                    self.device_display_diagonal_mils = ::std::option::Option::Some(is.read_int32()?);
                 },
-                405 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.mobile_data_supported = ::std::option::Option::Some(tmp);
+                192 => {
+                    self.device_authzen_version = ::std::option::Option::Some(is.read_int32()?);
                 },
-                406 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.tethering_supported = ::std::option::Option::Some(tmp);
+                234 => {
+                    self.long_device_id = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                407 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.ble_radio_supported = ::std::option::Option::Some(tmp);
+                250 => {
+                    self.device_manufacturer = ::std::option::Option::Some(is.read_string()?);
                 },
-                408 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.pixel_experience = ::std::option::Option::Some(tmp);
+                256 => {
+                    self.device_type = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                409 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.arc_plus_plus = ::std::option::Option::Some(tmp);
+                3200 => {
+                    self.using_secure_screenlock = ::std::option::Option::Some(is.read_bool()?);
                 },
-                410 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.is_screenlock_state_flaky = ::std::option::Option::Some(tmp);
+                3208 => {
+                    self.auto_unlock_screenlock_supported = ::std::option::Option::Some(is.read_bool()?);
                 },
-                411 => {
-                    ::protobuf::rt::read_repeated_enum_with_unknown_fields_into(wire_type, is, &mut self.supported_software_features, 411, &mut self.unknown_fields)?
+                3216 => {
+                    self.auto_unlock_screenlock_enabled = ::std::option::Option::Some(is.read_bool()?);
                 },
-                412 => {
-                    ::protobuf::rt::read_repeated_enum_with_unknown_fields_into(wire_type, is, &mut self.enabled_software_features, 412, &mut self.unknown_fields)?
+                3224 => {
+                    self.bluetooth_radio_supported = ::std::option::Option::Some(is.read_bool()?);
                 },
-                1000 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.enrollment_session_id)?;
+                3232 => {
+                    self.bluetooth_radio_enabled = ::std::option::Option::Some(is.read_bool()?);
                 },
-                1001 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.oauth_token)?;
+                3240 => {
+                    self.mobile_data_supported = ::std::option::Option::Some(is.read_bool()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                3248 => {
+                    self.tethering_supported = ::std::option::Option::Some(is.read_bool()?);
+                },
+                3256 => {
+                    self.ble_radio_supported = ::std::option::Option::Some(is.read_bool()?);
+                },
+                3264 => {
+                    self.pixel_experience = ::std::option::Option::Some(is.read_bool()?);
+                },
+                3272 => {
+                    self.arc_plus_plus = ::std::option::Option::Some(is.read_bool()?);
+                },
+                3280 => {
+                    self.is_screenlock_state_flaky = ::std::option::Option::Some(is.read_bool()?);
+                },
+                3288 => {
+                    self.supported_software_features.push(is.read_enum_or_unknown()?);
+                },
+                3290 => {
+                    ::protobuf::rt::read_repeated_packed_enum_or_unknown_into(is, &mut self.supported_software_features)?
+                },
+                3296 => {
+                    self.enabled_software_features.push(is.read_enum_or_unknown()?);
+                },
+                3298 => {
+                    ::protobuf::rt::read_repeated_packed_enum_or_unknown_into(is, &mut self.enabled_software_features)?
+                },
+                8002 => {
+                    self.enrollment_session_id = ::std::option::Option::Some(is.read_bytes()?);
+                },
+                8010 => {
+                    self.oauth_token = ::std::option::Option::Some(is.read_string()?);
+                },
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1326,181 +1256,181 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.android_device_id {
-            my_size += 9;
+            my_size += 1 + 8;
         }
-        if let Some(ref v) = self.gcm_registration_id.as_ref() {
+        if let Some(v) = self.gcm_registration_id.as_ref() {
             my_size += ::protobuf::rt::bytes_size(102, &v);
         }
-        if let Some(ref v) = self.apn_registration_id.as_ref() {
+        if let Some(v) = self.apn_registration_id.as_ref() {
             my_size += ::protobuf::rt::bytes_size(202, &v);
         }
         if let Some(v) = self.notification_enabled {
-            my_size += 3;
+            my_size += 2 + 1;
         }
-        if let Some(ref v) = self.bluetooth_mac_address.as_ref() {
+        if let Some(v) = self.bluetooth_mac_address.as_ref() {
             my_size += ::protobuf::rt::string_size(302, &v);
         }
-        if let Some(ref v) = self.device_master_key_hash.as_ref() {
+        if let Some(v) = self.device_master_key_hash.as_ref() {
             my_size += ::protobuf::rt::bytes_size(103, &v);
         }
-        if let Some(ref v) = self.user_public_key.as_ref() {
+        if let Some(v) = self.user_public_key.as_ref() {
             my_size += ::protobuf::rt::bytes_size(4, &v);
         }
-        if let Some(ref v) = self.device_model.as_ref() {
+        if let Some(v) = self.device_model.as_ref() {
             my_size += ::protobuf::rt::string_size(7, &v);
         }
-        if let Some(ref v) = self.locale.as_ref() {
+        if let Some(v) = self.locale.as_ref() {
             my_size += ::protobuf::rt::string_size(8, &v);
         }
-        if let Some(ref v) = self.key_handle.as_ref() {
+        if let Some(v) = self.key_handle.as_ref() {
             my_size += ::protobuf::rt::bytes_size(9, &v);
         }
         if let Some(v) = self.counter {
-            my_size += ::protobuf::rt::value_size(12, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int64_size(12, v);
         }
-        if let Some(ref v) = self.device_os_version.as_ref() {
+        if let Some(v) = self.device_os_version.as_ref() {
             my_size += ::protobuf::rt::string_size(13, &v);
         }
         if let Some(v) = self.device_os_version_code {
-            my_size += ::protobuf::rt::value_size(14, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int64_size(14, v);
         }
-        if let Some(ref v) = self.device_os_release.as_ref() {
+        if let Some(v) = self.device_os_release.as_ref() {
             my_size += ::protobuf::rt::string_size(15, &v);
         }
-        if let Some(ref v) = self.device_os_codename.as_ref() {
+        if let Some(v) = self.device_os_codename.as_ref() {
             my_size += ::protobuf::rt::string_size(16, &v);
         }
-        if let Some(ref v) = self.device_software_version.as_ref() {
+        if let Some(v) = self.device_software_version.as_ref() {
             my_size += ::protobuf::rt::string_size(17, &v);
         }
         if let Some(v) = self.device_software_version_code {
-            my_size += ::protobuf::rt::value_size(18, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int64_size(18, v);
         }
-        if let Some(ref v) = self.device_software_package.as_ref() {
+        if let Some(v) = self.device_software_package.as_ref() {
             my_size += ::protobuf::rt::string_size(19, &v);
         }
         if let Some(v) = self.device_display_diagonal_mils {
-            my_size += ::protobuf::rt::value_size(22, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(22, v);
         }
         if let Some(v) = self.device_authzen_version {
-            my_size += ::protobuf::rt::value_size(24, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(24, v);
         }
-        if let Some(ref v) = self.long_device_id.as_ref() {
+        if let Some(v) = self.long_device_id.as_ref() {
             my_size += ::protobuf::rt::bytes_size(29, &v);
         }
-        if let Some(ref v) = self.device_manufacturer.as_ref() {
+        if let Some(v) = self.device_manufacturer.as_ref() {
             my_size += ::protobuf::rt::string_size(31, &v);
         }
         if let Some(v) = self.device_type {
-            my_size += ::protobuf::rt::enum_size(32, v);
+            my_size += ::protobuf::rt::int32_size(32, v.value());
         }
         if let Some(v) = self.using_secure_screenlock {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.auto_unlock_screenlock_supported {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.auto_unlock_screenlock_enabled {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.bluetooth_radio_supported {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.bluetooth_radio_enabled {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.mobile_data_supported {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.tethering_supported {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.ble_radio_supported {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.pixel_experience {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.arc_plus_plus {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         if let Some(v) = self.is_screenlock_state_flaky {
-            my_size += 3;
+            my_size += 2 + 1;
         }
         for value in &self.supported_software_features {
-            my_size += ::protobuf::rt::enum_size(411, *value);
+            my_size += ::protobuf::rt::int32_size(411, value.value());
         };
         for value in &self.enabled_software_features {
-            my_size += ::protobuf::rt::enum_size(412, *value);
+            my_size += ::protobuf::rt::int32_size(412, value.value());
         };
-        if let Some(ref v) = self.enrollment_session_id.as_ref() {
+        if let Some(v) = self.enrollment_session_id.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1000, &v);
         }
-        if let Some(ref v) = self.oauth_token.as_ref() {
+        if let Some(v) = self.oauth_token.as_ref() {
             my_size += ::protobuf::rt::string_size(1001, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.android_device_id {
             os.write_fixed64(1, v)?;
         }
-        if let Some(ref v) = self.gcm_registration_id.as_ref() {
-            os.write_bytes(102, &v)?;
+        if let Some(v) = self.gcm_registration_id.as_ref() {
+            os.write_bytes(102, v)?;
         }
-        if let Some(ref v) = self.apn_registration_id.as_ref() {
-            os.write_bytes(202, &v)?;
+        if let Some(v) = self.apn_registration_id.as_ref() {
+            os.write_bytes(202, v)?;
         }
         if let Some(v) = self.notification_enabled {
             os.write_bool(203, v)?;
         }
-        if let Some(ref v) = self.bluetooth_mac_address.as_ref() {
-            os.write_string(302, &v)?;
+        if let Some(v) = self.bluetooth_mac_address.as_ref() {
+            os.write_string(302, v)?;
         }
-        if let Some(ref v) = self.device_master_key_hash.as_ref() {
-            os.write_bytes(103, &v)?;
+        if let Some(v) = self.device_master_key_hash.as_ref() {
+            os.write_bytes(103, v)?;
         }
-        if let Some(ref v) = self.user_public_key.as_ref() {
-            os.write_bytes(4, &v)?;
+        if let Some(v) = self.user_public_key.as_ref() {
+            os.write_bytes(4, v)?;
         }
-        if let Some(ref v) = self.device_model.as_ref() {
-            os.write_string(7, &v)?;
+        if let Some(v) = self.device_model.as_ref() {
+            os.write_string(7, v)?;
         }
-        if let Some(ref v) = self.locale.as_ref() {
-            os.write_string(8, &v)?;
+        if let Some(v) = self.locale.as_ref() {
+            os.write_string(8, v)?;
         }
-        if let Some(ref v) = self.key_handle.as_ref() {
-            os.write_bytes(9, &v)?;
+        if let Some(v) = self.key_handle.as_ref() {
+            os.write_bytes(9, v)?;
         }
         if let Some(v) = self.counter {
             os.write_int64(12, v)?;
         }
-        if let Some(ref v) = self.device_os_version.as_ref() {
-            os.write_string(13, &v)?;
+        if let Some(v) = self.device_os_version.as_ref() {
+            os.write_string(13, v)?;
         }
         if let Some(v) = self.device_os_version_code {
             os.write_int64(14, v)?;
         }
-        if let Some(ref v) = self.device_os_release.as_ref() {
-            os.write_string(15, &v)?;
+        if let Some(v) = self.device_os_release.as_ref() {
+            os.write_string(15, v)?;
         }
-        if let Some(ref v) = self.device_os_codename.as_ref() {
-            os.write_string(16, &v)?;
+        if let Some(v) = self.device_os_codename.as_ref() {
+            os.write_string(16, v)?;
         }
-        if let Some(ref v) = self.device_software_version.as_ref() {
-            os.write_string(17, &v)?;
+        if let Some(v) = self.device_software_version.as_ref() {
+            os.write_string(17, v)?;
         }
         if let Some(v) = self.device_software_version_code {
             os.write_int64(18, v)?;
         }
-        if let Some(ref v) = self.device_software_package.as_ref() {
-            os.write_string(19, &v)?;
+        if let Some(v) = self.device_software_package.as_ref() {
+            os.write_string(19, v)?;
         }
         if let Some(v) = self.device_display_diagonal_mils {
             os.write_int32(22, v)?;
@@ -1508,14 +1438,14 @@
         if let Some(v) = self.device_authzen_version {
             os.write_int32(24, v)?;
         }
-        if let Some(ref v) = self.long_device_id.as_ref() {
-            os.write_bytes(29, &v)?;
+        if let Some(v) = self.long_device_id.as_ref() {
+            os.write_bytes(29, v)?;
         }
-        if let Some(ref v) = self.device_manufacturer.as_ref() {
-            os.write_string(31, &v)?;
+        if let Some(v) = self.device_manufacturer.as_ref() {
+            os.write_string(31, v)?;
         }
         if let Some(v) = self.device_type {
-            os.write_enum(32, ::protobuf::ProtobufEnum::value(&v))?;
+            os.write_enum(32, ::protobuf::EnumOrUnknown::value(&v))?;
         }
         if let Some(v) = self.using_secure_screenlock {
             os.write_bool(400, v)?;
@@ -1551,81 +1481,56 @@
             os.write_bool(410, v)?;
         }
         for v in &self.supported_software_features {
-            os.write_enum(411, ::protobuf::ProtobufEnum::value(v))?;
+            os.write_enum(411, ::protobuf::EnumOrUnknown::value(v))?;
         };
         for v in &self.enabled_software_features {
-            os.write_enum(412, ::protobuf::ProtobufEnum::value(v))?;
+            os.write_enum(412, ::protobuf::EnumOrUnknown::value(v))?;
         };
-        if let Some(ref v) = self.enrollment_session_id.as_ref() {
-            os.write_bytes(1000, &v)?;
+        if let Some(v) = self.enrollment_session_id.as_ref() {
+            os.write_bytes(1000, v)?;
         }
-        if let Some(ref v) = self.oauth_token.as_ref() {
-            os.write_string(1001, &v)?;
+        if let Some(v) = self.oauth_token.as_ref() {
+            os.write_string(1001, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> GcmDeviceInfo {
         GcmDeviceInfo::new()
     }
 
-    fn default_instance() -> &'static GcmDeviceInfo {
-        static instance: ::protobuf::rt::LazyV2<GcmDeviceInfo> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(GcmDeviceInfo::new)
-    }
-}
-
-impl ::protobuf::Clear for GcmDeviceInfo {
     fn clear(&mut self) {
         self.android_device_id = ::std::option::Option::None;
-        self.gcm_registration_id.clear();
-        self.apn_registration_id.clear();
+        self.gcm_registration_id = ::std::option::Option::None;
+        self.apn_registration_id = ::std::option::Option::None;
         self.notification_enabled = ::std::option::Option::None;
-        self.bluetooth_mac_address.clear();
-        self.device_master_key_hash.clear();
-        self.user_public_key.clear();
-        self.device_model.clear();
-        self.locale.clear();
-        self.key_handle.clear();
+        self.bluetooth_mac_address = ::std::option::Option::None;
+        self.device_master_key_hash = ::std::option::Option::None;
+        self.user_public_key = ::std::option::Option::None;
+        self.device_model = ::std::option::Option::None;
+        self.locale = ::std::option::Option::None;
+        self.key_handle = ::std::option::Option::None;
         self.counter = ::std::option::Option::None;
-        self.device_os_version.clear();
+        self.device_os_version = ::std::option::Option::None;
         self.device_os_version_code = ::std::option::Option::None;
-        self.device_os_release.clear();
-        self.device_os_codename.clear();
-        self.device_software_version.clear();
+        self.device_os_release = ::std::option::Option::None;
+        self.device_os_codename = ::std::option::Option::None;
+        self.device_software_version = ::std::option::Option::None;
         self.device_software_version_code = ::std::option::Option::None;
-        self.device_software_package.clear();
+        self.device_software_package = ::std::option::Option::None;
         self.device_display_diagonal_mils = ::std::option::Option::None;
         self.device_authzen_version = ::std::option::Option::None;
-        self.long_device_id.clear();
-        self.device_manufacturer.clear();
+        self.long_device_id = ::std::option::Option::None;
+        self.device_manufacturer = ::std::option::Option::None;
         self.device_type = ::std::option::Option::None;
         self.using_secure_screenlock = ::std::option::Option::None;
         self.auto_unlock_screenlock_supported = ::std::option::Option::None;
@@ -1640,26 +1545,68 @@
         self.is_screenlock_state_flaky = ::std::option::Option::None;
         self.supported_software_features.clear();
         self.enabled_software_features.clear();
-        self.enrollment_session_id.clear();
-        self.oauth_token.clear();
-        self.unknown_fields.clear();
+        self.enrollment_session_id = ::std::option::Option::None;
+        self.oauth_token = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for GcmDeviceInfo {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static GcmDeviceInfo {
+        static instance: GcmDeviceInfo = GcmDeviceInfo {
+            android_device_id: ::std::option::Option::None,
+            gcm_registration_id: ::std::option::Option::None,
+            apn_registration_id: ::std::option::Option::None,
+            notification_enabled: ::std::option::Option::None,
+            bluetooth_mac_address: ::std::option::Option::None,
+            device_master_key_hash: ::std::option::Option::None,
+            user_public_key: ::std::option::Option::None,
+            device_model: ::std::option::Option::None,
+            locale: ::std::option::Option::None,
+            key_handle: ::std::option::Option::None,
+            counter: ::std::option::Option::None,
+            device_os_version: ::std::option::Option::None,
+            device_os_version_code: ::std::option::Option::None,
+            device_os_release: ::std::option::Option::None,
+            device_os_codename: ::std::option::Option::None,
+            device_software_version: ::std::option::Option::None,
+            device_software_version_code: ::std::option::Option::None,
+            device_software_package: ::std::option::Option::None,
+            device_display_diagonal_mils: ::std::option::Option::None,
+            device_authzen_version: ::std::option::Option::None,
+            long_device_id: ::std::option::Option::None,
+            device_manufacturer: ::std::option::Option::None,
+            device_type: ::std::option::Option::None,
+            using_secure_screenlock: ::std::option::Option::None,
+            auto_unlock_screenlock_supported: ::std::option::Option::None,
+            auto_unlock_screenlock_enabled: ::std::option::Option::None,
+            bluetooth_radio_supported: ::std::option::Option::None,
+            bluetooth_radio_enabled: ::std::option::Option::None,
+            mobile_data_supported: ::std::option::Option::None,
+            tethering_supported: ::std::option::Option::None,
+            ble_radio_supported: ::std::option::Option::None,
+            pixel_experience: ::std::option::Option::None,
+            arc_plus_plus: ::std::option::Option::None,
+            is_screenlock_state_flaky: ::std::option::Option::None,
+            supported_software_features: ::std::vec::Vec::new(),
+            enabled_software_features: ::std::vec::Vec::new(),
+            enrollment_session_id: ::std::option::Option::None,
+            oauth_token: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.GcmMetadata)
 pub struct GcmMetadata {
     // message fields
-    field_type: ::std::option::Option<Type>,
-    version: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.GcmMetadata.type)
+    pub type_: ::std::option::Option<::protobuf::EnumOrUnknown<Type>>,
+    // @@protoc_insertion_point(field:securegcm.GcmMetadata.version)
+    pub version: ::std::option::Option<i32>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.GcmMetadata.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a GcmMetadata {
@@ -1675,29 +1622,32 @@
 
     // required .securegcm.Type type = 1;
 
-
-    pub fn get_field_type(&self) -> Type {
-        self.field_type.unwrap_or(Type::ENROLLMENT)
-    }
-    pub fn clear_field_type(&mut self) {
-        self.field_type = ::std::option::Option::None;
+    pub fn type_(&self) -> Type {
+        match self.type_ {
+            Some(e) => e.enum_value_or(Type::ENROLLMENT),
+            None => Type::ENROLLMENT,
+        }
     }
 
-    pub fn has_field_type(&self) -> bool {
-        self.field_type.is_some()
+    pub fn clear_type_(&mut self) {
+        self.type_ = ::std::option::Option::None;
+    }
+
+    pub fn has_type(&self) -> bool {
+        self.type_.is_some()
     }
 
     // Param is passed by value, moved
-    pub fn set_field_type(&mut self, v: Type) {
-        self.field_type = ::std::option::Option::Some(v);
+    pub fn set_type(&mut self, v: Type) {
+        self.type_ = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // optional int32 version = 2;
 
-
-    pub fn get_version(&self) -> i32 {
+    pub fn version(&self) -> i32 {
         self.version.unwrap_or(0i32)
     }
+
     pub fn clear_version(&mut self) {
         self.version = ::std::option::Option::None;
     }
@@ -1713,29 +1663,26 @@
 }
 
 impl ::protobuf::Message for GcmMetadata {
+    const NAME: &'static str = "GcmMetadata";
+
     fn is_initialized(&self) -> bool {
-        if self.field_type.is_none() {
+        if self.type_.is_none() {
             return false;
         }
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 1, &mut self.unknown_fields)?
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.type_ = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.version = ::std::option::Option::Some(tmp);
+                16 => {
+                    self.version = ::std::option::Option::Some(is.read_int32()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1744,87 +1691,67 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(v) = self.field_type {
-            my_size += ::protobuf::rt::enum_size(1, v);
+        if let Some(v) = self.type_ {
+            my_size += ::protobuf::rt::int32_size(1, v.value());
         }
         if let Some(v) = self.version {
-            my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(2, v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(v) = self.field_type {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.type_ {
+            os.write_enum(1, ::protobuf::EnumOrUnknown::value(&v))?;
         }
         if let Some(v) = self.version {
             os.write_int32(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> GcmMetadata {
         GcmMetadata::new()
     }
 
-    fn default_instance() -> &'static GcmMetadata {
-        static instance: ::protobuf::rt::LazyV2<GcmMetadata> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(GcmMetadata::new)
-    }
-}
-
-impl ::protobuf::Clear for GcmMetadata {
     fn clear(&mut self) {
-        self.field_type = ::std::option::Option::None;
+        self.type_ = ::std::option::Option::None;
         self.version = ::std::option::Option::None;
-        self.unknown_fields.clear();
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for GcmMetadata {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static GcmMetadata {
+        static instance: GcmMetadata = GcmMetadata {
+            type_: ::std::option::Option::None,
+            version: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.Tickle)
 pub struct Tickle {
     // message fields
-    expiry_time: ::std::option::Option<u64>,
+    // @@protoc_insertion_point(field:securegcm.Tickle.expiry_time)
+    pub expiry_time: ::std::option::Option<u64>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.Tickle.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a Tickle {
@@ -1840,10 +1767,10 @@
 
     // optional fixed64 expiry_time = 1;
 
-
-    pub fn get_expiry_time(&self) -> u64 {
+    pub fn expiry_time(&self) -> u64 {
         self.expiry_time.unwrap_or(0)
     }
+
     pub fn clear_expiry_time(&mut self) {
         self.expiry_time = ::std::option::Option::None;
     }
@@ -1859,23 +1786,20 @@
 }
 
 impl ::protobuf::Message for Tickle {
+    const NAME: &'static str = "Tickle";
+
     fn is_initialized(&self) -> bool {
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeFixed64 {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_fixed64()?;
-                    self.expiry_time = ::std::option::Option::Some(tmp);
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                9 => {
+                    self.expiry_time = ::std::option::Option::Some(is.read_fixed64()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1884,84 +1808,67 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.expiry_time {
-            my_size += 9;
+            my_size += 1 + 8;
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.expiry_time {
             os.write_fixed64(1, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> Tickle {
         Tickle::new()
     }
 
-    fn default_instance() -> &'static Tickle {
-        static instance: ::protobuf::rt::LazyV2<Tickle> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Tickle::new)
-    }
-}
-
-impl ::protobuf::Clear for Tickle {
     fn clear(&mut self) {
         self.expiry_time = ::std::option::Option::None;
-        self.unknown_fields.clear();
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for Tickle {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static Tickle {
+        static instance: Tickle = Tickle {
+            expiry_time: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.LoginNotificationInfo)
 pub struct LoginNotificationInfo {
     // message fields
-    creation_time: ::std::option::Option<u64>,
-    email: ::protobuf::SingularField<::std::string::String>,
-    host: ::protobuf::SingularField<::std::string::String>,
-    source: ::protobuf::SingularField<::std::string::String>,
-    event_type: ::protobuf::SingularField<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.creation_time)
+    pub creation_time: ::std::option::Option<u64>,
+    // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.email)
+    pub email: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.host)
+    pub host: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.source)
+    pub source: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.event_type)
+    pub event_type: ::std::option::Option<::std::string::String>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.LoginNotificationInfo.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a LoginNotificationInfo {
@@ -1977,10 +1884,10 @@
 
     // optional fixed64 creation_time = 2;
 
-
-    pub fn get_creation_time(&self) -> u64 {
+    pub fn creation_time(&self) -> u64 {
         self.creation_time.unwrap_or(0)
     }
+
     pub fn clear_creation_time(&mut self) {
         self.creation_time = ::std::option::Option::None;
     }
@@ -1996,15 +1903,15 @@
 
     // optional string email = 3;
 
-
-    pub fn get_email(&self) -> &str {
+    pub fn email(&self) -> &str {
         match self.email.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_email(&mut self) {
-        self.email.clear();
+        self.email = ::std::option::Option::None;
     }
 
     pub fn has_email(&self) -> bool {
@@ -2013,14 +1920,14 @@
 
     // Param is passed by value, moved
     pub fn set_email(&mut self, v: ::std::string::String) {
-        self.email = ::protobuf::SingularField::some(v);
+        self.email = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_email(&mut self) -> &mut ::std::string::String {
         if self.email.is_none() {
-            self.email.set_default();
+            self.email = ::std::option::Option::Some(::std::string::String::new());
         }
         self.email.as_mut().unwrap()
     }
@@ -2032,15 +1939,15 @@
 
     // optional string host = 4;
 
-
-    pub fn get_host(&self) -> &str {
+    pub fn host(&self) -> &str {
         match self.host.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_host(&mut self) {
-        self.host.clear();
+        self.host = ::std::option::Option::None;
     }
 
     pub fn has_host(&self) -> bool {
@@ -2049,14 +1956,14 @@
 
     // Param is passed by value, moved
     pub fn set_host(&mut self, v: ::std::string::String) {
-        self.host = ::protobuf::SingularField::some(v);
+        self.host = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_host(&mut self) -> &mut ::std::string::String {
         if self.host.is_none() {
-            self.host.set_default();
+            self.host = ::std::option::Option::Some(::std::string::String::new());
         }
         self.host.as_mut().unwrap()
     }
@@ -2068,15 +1975,15 @@
 
     // optional string source = 5;
 
-
-    pub fn get_source(&self) -> &str {
+    pub fn source(&self) -> &str {
         match self.source.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_source(&mut self) {
-        self.source.clear();
+        self.source = ::std::option::Option::None;
     }
 
     pub fn has_source(&self) -> bool {
@@ -2085,14 +1992,14 @@
 
     // Param is passed by value, moved
     pub fn set_source(&mut self, v: ::std::string::String) {
-        self.source = ::protobuf::SingularField::some(v);
+        self.source = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_source(&mut self) -> &mut ::std::string::String {
         if self.source.is_none() {
-            self.source.set_default();
+            self.source = ::std::option::Option::Some(::std::string::String::new());
         }
         self.source.as_mut().unwrap()
     }
@@ -2104,15 +2011,15 @@
 
     // optional string event_type = 6;
 
-
-    pub fn get_event_type(&self) -> &str {
+    pub fn event_type(&self) -> &str {
         match self.event_type.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_event_type(&mut self) {
-        self.event_type.clear();
+        self.event_type = ::std::option::Option::None;
     }
 
     pub fn has_event_type(&self) -> bool {
@@ -2121,14 +2028,14 @@
 
     // Param is passed by value, moved
     pub fn set_event_type(&mut self, v: ::std::string::String) {
-        self.event_type = ::protobuf::SingularField::some(v);
+        self.event_type = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_event_type(&mut self) -> &mut ::std::string::String {
         if self.event_type.is_none() {
-            self.event_type.set_default();
+            self.event_type = ::std::option::Option::Some(::std::string::String::new());
         }
         self.event_type.as_mut().unwrap()
     }
@@ -2140,35 +2047,32 @@
 }
 
 impl ::protobuf::Message for LoginNotificationInfo {
+    const NAME: &'static str = "LoginNotificationInfo";
+
     fn is_initialized(&self) -> bool {
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeFixed64 {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_fixed64()?;
-                    self.creation_time = ::std::option::Option::Some(tmp);
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                17 => {
+                    self.creation_time = ::std::option::Option::Some(is.read_fixed64()?);
                 },
-                3 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.email)?;
+                26 => {
+                    self.email = ::std::option::Option::Some(is.read_string()?);
                 },
-                4 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.host)?;
+                34 => {
+                    self.host = ::std::option::Option::Some(is.read_string()?);
                 },
-                5 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.source)?;
+                42 => {
+                    self.source = ::std::option::Option::Some(is.read_string()?);
                 },
-                6 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.event_type)?;
+                50 => {
+                    self.event_type = ::std::option::Option::Some(is.read_string()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -2177,108 +2081,94 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.creation_time {
-            my_size += 9;
+            my_size += 1 + 8;
         }
-        if let Some(ref v) = self.email.as_ref() {
+        if let Some(v) = self.email.as_ref() {
             my_size += ::protobuf::rt::string_size(3, &v);
         }
-        if let Some(ref v) = self.host.as_ref() {
+        if let Some(v) = self.host.as_ref() {
             my_size += ::protobuf::rt::string_size(4, &v);
         }
-        if let Some(ref v) = self.source.as_ref() {
+        if let Some(v) = self.source.as_ref() {
             my_size += ::protobuf::rt::string_size(5, &v);
         }
-        if let Some(ref v) = self.event_type.as_ref() {
+        if let Some(v) = self.event_type.as_ref() {
             my_size += ::protobuf::rt::string_size(6, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.creation_time {
             os.write_fixed64(2, v)?;
         }
-        if let Some(ref v) = self.email.as_ref() {
-            os.write_string(3, &v)?;
+        if let Some(v) = self.email.as_ref() {
+            os.write_string(3, v)?;
         }
-        if let Some(ref v) = self.host.as_ref() {
-            os.write_string(4, &v)?;
+        if let Some(v) = self.host.as_ref() {
+            os.write_string(4, v)?;
         }
-        if let Some(ref v) = self.source.as_ref() {
-            os.write_string(5, &v)?;
+        if let Some(v) = self.source.as_ref() {
+            os.write_string(5, v)?;
         }
-        if let Some(ref v) = self.event_type.as_ref() {
-            os.write_string(6, &v)?;
+        if let Some(v) = self.event_type.as_ref() {
+            os.write_string(6, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> LoginNotificationInfo {
         LoginNotificationInfo::new()
     }
 
-    fn default_instance() -> &'static LoginNotificationInfo {
-        static instance: ::protobuf::rt::LazyV2<LoginNotificationInfo> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(LoginNotificationInfo::new)
-    }
-}
-
-impl ::protobuf::Clear for LoginNotificationInfo {
     fn clear(&mut self) {
         self.creation_time = ::std::option::Option::None;
-        self.email.clear();
-        self.host.clear();
-        self.source.clear();
-        self.event_type.clear();
-        self.unknown_fields.clear();
+        self.email = ::std::option::Option::None;
+        self.host = ::std::option::Option::None;
+        self.source = ::std::option::Option::None;
+        self.event_type = ::std::option::Option::None;
+        self.special_fields.clear();
+    }
+
+    fn default_instance() -> &'static LoginNotificationInfo {
+        static instance: LoginNotificationInfo = LoginNotificationInfo {
+            creation_time: ::std::option::Option::None,
+            email: ::std::option::Option::None,
+            host: ::std::option::Option::None,
+            source: ::std::option::Option::None,
+            event_type: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for LoginNotificationInfo {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securegcm.AppleDeviceDiagonalMils)
 pub enum AppleDeviceDiagonalMils {
+    // @@protoc_insertion_point(enum_value:securegcm.AppleDeviceDiagonalMils.APPLE_PHONE)
     APPLE_PHONE = 4000,
+    // @@protoc_insertion_point(enum_value:securegcm.AppleDeviceDiagonalMils.APPLE_PAD)
     APPLE_PAD = 7900,
 }
 
-impl ::protobuf::ProtobufEnum for AppleDeviceDiagonalMils {
+impl ::protobuf::Enum for AppleDeviceDiagonalMils {
+    const NAME: &'static str = "AppleDeviceDiagonalMils";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -2291,16 +2181,10 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [AppleDeviceDiagonalMils] = &[
-            AppleDeviceDiagonalMils::APPLE_PHONE,
-            AppleDeviceDiagonalMils::APPLE_PAD,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for AppleDeviceDiagonalMils {
+    const VALUES: &'static [AppleDeviceDiagonalMils] = &[
+        AppleDeviceDiagonalMils::APPLE_PHONE,
+        AppleDeviceDiagonalMils::APPLE_PAD,
+    ];
 }
 
 // Note, `Default` is implemented although default value is not 0
@@ -2310,23 +2194,27 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for AppleDeviceDiagonalMils {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
 
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securegcm.DeviceType)
 pub enum DeviceType {
+    // @@protoc_insertion_point(enum_value:securegcm.DeviceType.UNKNOWN)
     UNKNOWN = 0,
+    // @@protoc_insertion_point(enum_value:securegcm.DeviceType.ANDROID)
     ANDROID = 1,
+    // @@protoc_insertion_point(enum_value:securegcm.DeviceType.CHROME)
     CHROME = 2,
+    // @@protoc_insertion_point(enum_value:securegcm.DeviceType.IOS)
     IOS = 3,
+    // @@protoc_insertion_point(enum_value:securegcm.DeviceType.BROWSER)
     BROWSER = 4,
+    // @@protoc_insertion_point(enum_value:securegcm.DeviceType.OSX)
     OSX = 5,
 }
 
-impl ::protobuf::ProtobufEnum for DeviceType {
+impl ::protobuf::Enum for DeviceType {
+    const NAME: &'static str = "DeviceType";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -2343,20 +2231,14 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [DeviceType] = &[
-            DeviceType::UNKNOWN,
-            DeviceType::ANDROID,
-            DeviceType::CHROME,
-            DeviceType::IOS,
-            DeviceType::BROWSER,
-            DeviceType::OSX,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for DeviceType {
+    const VALUES: &'static [DeviceType] = &[
+        DeviceType::UNKNOWN,
+        DeviceType::ANDROID,
+        DeviceType::CHROME,
+        DeviceType::IOS,
+        DeviceType::BROWSER,
+        DeviceType::OSX,
+    ];
 }
 
 impl ::std::default::Default for DeviceType {
@@ -2365,26 +2247,33 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for DeviceType {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
 
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securegcm.SoftwareFeature)
 pub enum SoftwareFeature {
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.UNKNOWN_FEATURE)
     UNKNOWN_FEATURE = 0,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.BETTER_TOGETHER_HOST)
     BETTER_TOGETHER_HOST = 1,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.BETTER_TOGETHER_CLIENT)
     BETTER_TOGETHER_CLIENT = 2,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.EASY_UNLOCK_HOST)
     EASY_UNLOCK_HOST = 3,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.EASY_UNLOCK_CLIENT)
     EASY_UNLOCK_CLIENT = 4,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.MAGIC_TETHER_HOST)
     MAGIC_TETHER_HOST = 5,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.MAGIC_TETHER_CLIENT)
     MAGIC_TETHER_CLIENT = 6,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.SMS_CONNECT_HOST)
     SMS_CONNECT_HOST = 7,
+    // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.SMS_CONNECT_CLIENT)
     SMS_CONNECT_CLIENT = 8,
 }
 
-impl ::protobuf::ProtobufEnum for SoftwareFeature {
+impl ::protobuf::Enum for SoftwareFeature {
+    const NAME: &'static str = "SoftwareFeature";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -2404,23 +2293,17 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [SoftwareFeature] = &[
-            SoftwareFeature::UNKNOWN_FEATURE,
-            SoftwareFeature::BETTER_TOGETHER_HOST,
-            SoftwareFeature::BETTER_TOGETHER_CLIENT,
-            SoftwareFeature::EASY_UNLOCK_HOST,
-            SoftwareFeature::EASY_UNLOCK_CLIENT,
-            SoftwareFeature::MAGIC_TETHER_HOST,
-            SoftwareFeature::MAGIC_TETHER_CLIENT,
-            SoftwareFeature::SMS_CONNECT_HOST,
-            SoftwareFeature::SMS_CONNECT_CLIENT,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for SoftwareFeature {
+    const VALUES: &'static [SoftwareFeature] = &[
+        SoftwareFeature::UNKNOWN_FEATURE,
+        SoftwareFeature::BETTER_TOGETHER_HOST,
+        SoftwareFeature::BETTER_TOGETHER_CLIENT,
+        SoftwareFeature::EASY_UNLOCK_HOST,
+        SoftwareFeature::EASY_UNLOCK_CLIENT,
+        SoftwareFeature::MAGIC_TETHER_HOST,
+        SoftwareFeature::MAGIC_TETHER_CLIENT,
+        SoftwareFeature::SMS_CONNECT_HOST,
+        SoftwareFeature::SMS_CONNECT_CLIENT,
+    ];
 }
 
 impl ::std::default::Default for SoftwareFeature {
@@ -2429,33 +2312,47 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for SoftwareFeature {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
 
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securegcm.InvocationReason)
 pub enum InvocationReason {
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_UNKNOWN)
     REASON_UNKNOWN = 0,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_INITIALIZATION)
     REASON_INITIALIZATION = 1,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_PERIODIC)
     REASON_PERIODIC = 2,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_SLOW_PERIODIC)
     REASON_SLOW_PERIODIC = 3,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_FAST_PERIODIC)
     REASON_FAST_PERIODIC = 4,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_EXPIRATION)
     REASON_EXPIRATION = 5,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_FAILURE_RECOVERY)
     REASON_FAILURE_RECOVERY = 6,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_NEW_ACCOUNT)
     REASON_NEW_ACCOUNT = 7,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_CHANGED_ACCOUNT)
     REASON_CHANGED_ACCOUNT = 8,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_FEATURE_TOGGLED)
     REASON_FEATURE_TOGGLED = 9,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_SERVER_INITIATED)
     REASON_SERVER_INITIATED = 10,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_ADDRESS_CHANGE)
     REASON_ADDRESS_CHANGE = 11,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_SOFTWARE_UPDATE)
     REASON_SOFTWARE_UPDATE = 12,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_MANUAL)
     REASON_MANUAL = 13,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_CUSTOM_KEY_INVALIDATION)
     REASON_CUSTOM_KEY_INVALIDATION = 14,
+    // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_PROXIMITY_PERIODIC)
     REASON_PROXIMITY_PERIODIC = 15,
 }
 
-impl ::protobuf::ProtobufEnum for InvocationReason {
+impl ::protobuf::Enum for InvocationReason {
+    const NAME: &'static str = "InvocationReason";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -2482,30 +2379,24 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [InvocationReason] = &[
-            InvocationReason::REASON_UNKNOWN,
-            InvocationReason::REASON_INITIALIZATION,
-            InvocationReason::REASON_PERIODIC,
-            InvocationReason::REASON_SLOW_PERIODIC,
-            InvocationReason::REASON_FAST_PERIODIC,
-            InvocationReason::REASON_EXPIRATION,
-            InvocationReason::REASON_FAILURE_RECOVERY,
-            InvocationReason::REASON_NEW_ACCOUNT,
-            InvocationReason::REASON_CHANGED_ACCOUNT,
-            InvocationReason::REASON_FEATURE_TOGGLED,
-            InvocationReason::REASON_SERVER_INITIATED,
-            InvocationReason::REASON_ADDRESS_CHANGE,
-            InvocationReason::REASON_SOFTWARE_UPDATE,
-            InvocationReason::REASON_MANUAL,
-            InvocationReason::REASON_CUSTOM_KEY_INVALIDATION,
-            InvocationReason::REASON_PROXIMITY_PERIODIC,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for InvocationReason {
+    const VALUES: &'static [InvocationReason] = &[
+        InvocationReason::REASON_UNKNOWN,
+        InvocationReason::REASON_INITIALIZATION,
+        InvocationReason::REASON_PERIODIC,
+        InvocationReason::REASON_SLOW_PERIODIC,
+        InvocationReason::REASON_FAST_PERIODIC,
+        InvocationReason::REASON_EXPIRATION,
+        InvocationReason::REASON_FAILURE_RECOVERY,
+        InvocationReason::REASON_NEW_ACCOUNT,
+        InvocationReason::REASON_CHANGED_ACCOUNT,
+        InvocationReason::REASON_FEATURE_TOGGLED,
+        InvocationReason::REASON_SERVER_INITIATED,
+        InvocationReason::REASON_ADDRESS_CHANGE,
+        InvocationReason::REASON_SOFTWARE_UPDATE,
+        InvocationReason::REASON_MANUAL,
+        InvocationReason::REASON_CUSTOM_KEY_INVALIDATION,
+        InvocationReason::REASON_PROXIMITY_PERIODIC,
+    ];
 }
 
 impl ::std::default::Default for InvocationReason {
@@ -2514,33 +2405,47 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for InvocationReason {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
 
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securegcm.Type)
 pub enum Type {
+    // @@protoc_insertion_point(enum_value:securegcm.Type.ENROLLMENT)
     ENROLLMENT = 0,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.TICKLE)
     TICKLE = 1,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.TX_REQUEST)
     TX_REQUEST = 2,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.TX_REPLY)
     TX_REPLY = 3,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.TX_SYNC_REQUEST)
     TX_SYNC_REQUEST = 4,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.TX_SYNC_RESPONSE)
     TX_SYNC_RESPONSE = 5,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.TX_PING)
     TX_PING = 6,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.DEVICE_INFO_UPDATE)
     DEVICE_INFO_UPDATE = 7,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.TX_CANCEL_REQUEST)
     TX_CANCEL_REQUEST = 8,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.PROXIMITYAUTH_PAIRING)
     PROXIMITYAUTH_PAIRING = 10,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.GCMV1_IDENTITY_ASSERTION)
     GCMV1_IDENTITY_ASSERTION = 11,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD)
     DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD = 12,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.DEVICE_TO_DEVICE_MESSAGE)
     DEVICE_TO_DEVICE_MESSAGE = 13,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.DEVICE_PROXIMITY_CALLBACK)
     DEVICE_PROXIMITY_CALLBACK = 14,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.UNLOCK_KEY_SIGNED_CHALLENGE)
     UNLOCK_KEY_SIGNED_CHALLENGE = 15,
+    // @@protoc_insertion_point(enum_value:securegcm.Type.LOGIN_NOTIFICATION)
     LOGIN_NOTIFICATION = 101,
 }
 
-impl ::protobuf::ProtobufEnum for Type {
+impl ::protobuf::Enum for Type {
+    const NAME: &'static str = "Type";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -2567,30 +2472,24 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [Type] = &[
-            Type::ENROLLMENT,
-            Type::TICKLE,
-            Type::TX_REQUEST,
-            Type::TX_REPLY,
-            Type::TX_SYNC_REQUEST,
-            Type::TX_SYNC_RESPONSE,
-            Type::TX_PING,
-            Type::DEVICE_INFO_UPDATE,
-            Type::TX_CANCEL_REQUEST,
-            Type::PROXIMITYAUTH_PAIRING,
-            Type::GCMV1_IDENTITY_ASSERTION,
-            Type::DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD,
-            Type::DEVICE_TO_DEVICE_MESSAGE,
-            Type::DEVICE_PROXIMITY_CALLBACK,
-            Type::UNLOCK_KEY_SIGNED_CHALLENGE,
-            Type::LOGIN_NOTIFICATION,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for Type {
+    const VALUES: &'static [Type] = &[
+        Type::ENROLLMENT,
+        Type::TICKLE,
+        Type::TX_REQUEST,
+        Type::TX_REPLY,
+        Type::TX_SYNC_REQUEST,
+        Type::TX_SYNC_RESPONSE,
+        Type::TX_PING,
+        Type::DEVICE_INFO_UPDATE,
+        Type::TX_CANCEL_REQUEST,
+        Type::PROXIMITYAUTH_PAIRING,
+        Type::GCMV1_IDENTITY_ASSERTION,
+        Type::DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD,
+        Type::DEVICE_TO_DEVICE_MESSAGE,
+        Type::DEVICE_PROXIMITY_CALLBACK,
+        Type::UNLOCK_KEY_SIGNED_CHALLENGE,
+        Type::LOGIN_NOTIFICATION,
+    ];
 }
 
 impl ::std::default::Default for Type {
@@ -2599,8 +2498,3 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for Type {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs
index e3df251..161e0be 100644
--- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs
+++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs
@@ -12,7 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// This file is generated by rust-protobuf 2.28.0. Do not edit
+// This file is generated by rust-protobuf 3.2.0. Do not edit
+// .proto file is parsed by protoc 3.19.1
 // @generated
 
 // https://github.com/rust-lang/rust-clippy/issues/702
@@ -29,22 +30,27 @@
 #![allow(non_snake_case)]
 #![allow(non_upper_case_globals)]
 #![allow(trivial_casts)]
-#![allow(unused_imports)]
 #![allow(unused_results)]
+#![allow(unused_mut)]
+
 //! Generated file from `securemessage.proto`
+// Generated for lite runtime
 
 /// Generated files are compatible only with the same version
 /// of protobuf runtime.
-// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_28_0;
+const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.SecureMessage)
 pub struct SecureMessage {
     // message fields
-    header_and_body: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    signature: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.SecureMessage.header_and_body)
+    pub header_and_body: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.SecureMessage.signature)
+    pub signature: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.SecureMessage.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a SecureMessage {
@@ -60,15 +66,15 @@
 
     // required bytes header_and_body = 1;
 
-
-    pub fn get_header_and_body(&self) -> &[u8] {
+    pub fn header_and_body(&self) -> &[u8] {
         match self.header_and_body.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_header_and_body(&mut self) {
-        self.header_and_body.clear();
+        self.header_and_body = ::std::option::Option::None;
     }
 
     pub fn has_header_and_body(&self) -> bool {
@@ -77,14 +83,14 @@
 
     // Param is passed by value, moved
     pub fn set_header_and_body(&mut self, v: ::std::vec::Vec<u8>) {
-        self.header_and_body = ::protobuf::SingularField::some(v);
+        self.header_and_body = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_header_and_body(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.header_and_body.is_none() {
-            self.header_and_body.set_default();
+            self.header_and_body = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.header_and_body.as_mut().unwrap()
     }
@@ -96,15 +102,15 @@
 
     // required bytes signature = 2;
 
-
-    pub fn get_signature(&self) -> &[u8] {
+    pub fn signature(&self) -> &[u8] {
         match self.signature.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_signature(&mut self) {
-        self.signature.clear();
+        self.signature = ::std::option::Option::None;
     }
 
     pub fn has_signature(&self) -> bool {
@@ -113,14 +119,14 @@
 
     // Param is passed by value, moved
     pub fn set_signature(&mut self, v: ::std::vec::Vec<u8>) {
-        self.signature = ::protobuf::SingularField::some(v);
+        self.signature = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_signature(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.signature.is_none() {
-            self.signature.set_default();
+            self.signature = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.signature.as_mut().unwrap()
     }
@@ -132,6 +138,8 @@
 }
 
 impl ::protobuf::Message for SecureMessage {
+    const NAME: &'static str = "SecureMessage";
+
     fn is_initialized(&self) -> bool {
         if self.header_and_body.is_none() {
             return false;
@@ -142,18 +150,17 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.header_and_body)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    self.header_and_body = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.signature)?;
+                18 => {
+                    self.signature = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -162,93 +169,81 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.header_and_body.as_ref() {
+        if let Some(v) = self.header_and_body.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1, &v);
         }
-        if let Some(ref v) = self.signature.as_ref() {
+        if let Some(v) = self.signature.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.header_and_body.as_ref() {
-            os.write_bytes(1, &v)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.header_and_body.as_ref() {
+            os.write_bytes(1, v)?;
         }
-        if let Some(ref v) = self.signature.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.signature.as_ref() {
+            os.write_bytes(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> SecureMessage {
         SecureMessage::new()
     }
 
-    fn default_instance() -> &'static SecureMessage {
-        static instance: ::protobuf::rt::LazyV2<SecureMessage> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(SecureMessage::new)
-    }
-}
-
-impl ::protobuf::Clear for SecureMessage {
     fn clear(&mut self) {
-        self.header_and_body.clear();
-        self.signature.clear();
-        self.unknown_fields.clear();
+        self.header_and_body = ::std::option::Option::None;
+        self.signature = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for SecureMessage {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static SecureMessage {
+        static instance: SecureMessage = SecureMessage {
+            header_and_body: ::std::option::Option::None,
+            signature: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.Header)
 pub struct Header {
     // message fields
-    signature_scheme: ::std::option::Option<SigScheme>,
-    encryption_scheme: ::std::option::Option<EncScheme>,
-    verification_key_id: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    decryption_key_id: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    iv: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    public_metadata: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    associated_data_length: ::std::option::Option<u32>,
+    // @@protoc_insertion_point(field:securemessage.Header.signature_scheme)
+    pub signature_scheme: ::std::option::Option<::protobuf::EnumOrUnknown<SigScheme>>,
+    // @@protoc_insertion_point(field:securemessage.Header.encryption_scheme)
+    pub encryption_scheme: ::std::option::Option<::protobuf::EnumOrUnknown<EncScheme>>,
+    // @@protoc_insertion_point(field:securemessage.Header.verification_key_id)
+    pub verification_key_id: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.Header.decryption_key_id)
+    pub decryption_key_id: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.Header.iv)
+    pub iv: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.Header.public_metadata)
+    pub public_metadata: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.Header.associated_data_length)
+    pub associated_data_length: ::std::option::Option<u32>,
+    // @@protoc_insertion_point(field:securemessage.Header.nonce)
+    pub nonce: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.Header.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a Header {
@@ -264,10 +259,13 @@
 
     // required .securemessage.SigScheme signature_scheme = 1;
 
-
-    pub fn get_signature_scheme(&self) -> SigScheme {
-        self.signature_scheme.unwrap_or(SigScheme::HMAC_SHA256)
+    pub fn signature_scheme(&self) -> SigScheme {
+        match self.signature_scheme {
+            Some(e) => e.enum_value_or(SigScheme::HMAC_SHA256),
+            None => SigScheme::HMAC_SHA256,
+        }
     }
+
     pub fn clear_signature_scheme(&mut self) {
         self.signature_scheme = ::std::option::Option::None;
     }
@@ -278,15 +276,18 @@
 
     // Param is passed by value, moved
     pub fn set_signature_scheme(&mut self, v: SigScheme) {
-        self.signature_scheme = ::std::option::Option::Some(v);
+        self.signature_scheme = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // required .securemessage.EncScheme encryption_scheme = 2;
 
-
-    pub fn get_encryption_scheme(&self) -> EncScheme {
-        self.encryption_scheme.unwrap_or(EncScheme::NONE)
+    pub fn encryption_scheme(&self) -> EncScheme {
+        match self.encryption_scheme {
+            Some(e) => e.enum_value_or(EncScheme::NONE),
+            None => EncScheme::NONE,
+        }
     }
+
     pub fn clear_encryption_scheme(&mut self) {
         self.encryption_scheme = ::std::option::Option::None;
     }
@@ -297,20 +298,20 @@
 
     // Param is passed by value, moved
     pub fn set_encryption_scheme(&mut self, v: EncScheme) {
-        self.encryption_scheme = ::std::option::Option::Some(v);
+        self.encryption_scheme = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // optional bytes verification_key_id = 3;
 
-
-    pub fn get_verification_key_id(&self) -> &[u8] {
+    pub fn verification_key_id(&self) -> &[u8] {
         match self.verification_key_id.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_verification_key_id(&mut self) {
-        self.verification_key_id.clear();
+        self.verification_key_id = ::std::option::Option::None;
     }
 
     pub fn has_verification_key_id(&self) -> bool {
@@ -319,14 +320,14 @@
 
     // Param is passed by value, moved
     pub fn set_verification_key_id(&mut self, v: ::std::vec::Vec<u8>) {
-        self.verification_key_id = ::protobuf::SingularField::some(v);
+        self.verification_key_id = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_verification_key_id(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.verification_key_id.is_none() {
-            self.verification_key_id.set_default();
+            self.verification_key_id = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.verification_key_id.as_mut().unwrap()
     }
@@ -338,15 +339,15 @@
 
     // optional bytes decryption_key_id = 4;
 
-
-    pub fn get_decryption_key_id(&self) -> &[u8] {
+    pub fn decryption_key_id(&self) -> &[u8] {
         match self.decryption_key_id.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_decryption_key_id(&mut self) {
-        self.decryption_key_id.clear();
+        self.decryption_key_id = ::std::option::Option::None;
     }
 
     pub fn has_decryption_key_id(&self) -> bool {
@@ -355,14 +356,14 @@
 
     // Param is passed by value, moved
     pub fn set_decryption_key_id(&mut self, v: ::std::vec::Vec<u8>) {
-        self.decryption_key_id = ::protobuf::SingularField::some(v);
+        self.decryption_key_id = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_decryption_key_id(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.decryption_key_id.is_none() {
-            self.decryption_key_id.set_default();
+            self.decryption_key_id = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.decryption_key_id.as_mut().unwrap()
     }
@@ -374,15 +375,15 @@
 
     // optional bytes iv = 5;
 
-
-    pub fn get_iv(&self) -> &[u8] {
+    pub fn iv(&self) -> &[u8] {
         match self.iv.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_iv(&mut self) {
-        self.iv.clear();
+        self.iv = ::std::option::Option::None;
     }
 
     pub fn has_iv(&self) -> bool {
@@ -391,14 +392,14 @@
 
     // Param is passed by value, moved
     pub fn set_iv(&mut self, v: ::std::vec::Vec<u8>) {
-        self.iv = ::protobuf::SingularField::some(v);
+        self.iv = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_iv(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.iv.is_none() {
-            self.iv.set_default();
+            self.iv = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.iv.as_mut().unwrap()
     }
@@ -410,15 +411,15 @@
 
     // optional bytes public_metadata = 6;
 
-
-    pub fn get_public_metadata(&self) -> &[u8] {
+    pub fn public_metadata(&self) -> &[u8] {
         match self.public_metadata.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_public_metadata(&mut self) {
-        self.public_metadata.clear();
+        self.public_metadata = ::std::option::Option::None;
     }
 
     pub fn has_public_metadata(&self) -> bool {
@@ -427,14 +428,14 @@
 
     // Param is passed by value, moved
     pub fn set_public_metadata(&mut self, v: ::std::vec::Vec<u8>) {
-        self.public_metadata = ::protobuf::SingularField::some(v);
+        self.public_metadata = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_public_metadata(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.public_metadata.is_none() {
-            self.public_metadata.set_default();
+            self.public_metadata = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.public_metadata.as_mut().unwrap()
     }
@@ -446,10 +447,10 @@
 
     // optional uint32 associated_data_length = 7;
 
-
-    pub fn get_associated_data_length(&self) -> u32 {
+    pub fn associated_data_length(&self) -> u32 {
         self.associated_data_length.unwrap_or(0u32)
     }
+
     pub fn clear_associated_data_length(&mut self) {
         self.associated_data_length = ::std::option::Option::None;
     }
@@ -462,9 +463,47 @@
     pub fn set_associated_data_length(&mut self, v: u32) {
         self.associated_data_length = ::std::option::Option::Some(v);
     }
+
+    // optional bytes nonce = 8;
+
+    pub fn nonce(&self) -> &[u8] {
+        match self.nonce.as_ref() {
+            Some(v) => v,
+            None => &[],
+        }
+    }
+
+    pub fn clear_nonce(&mut self) {
+        self.nonce = ::std::option::Option::None;
+    }
+
+    pub fn has_nonce(&self) -> bool {
+        self.nonce.is_some()
+    }
+
+    // Param is passed by value, moved
+    pub fn set_nonce(&mut self, v: ::std::vec::Vec<u8>) {
+        self.nonce = ::std::option::Option::Some(v);
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_nonce(&mut self) -> &mut ::std::vec::Vec<u8> {
+        if self.nonce.is_none() {
+            self.nonce = ::std::option::Option::Some(::std::vec::Vec::new());
+        }
+        self.nonce.as_mut().unwrap()
+    }
+
+    // Take field
+    pub fn take_nonce(&mut self) -> ::std::vec::Vec<u8> {
+        self.nonce.take().unwrap_or_else(|| ::std::vec::Vec::new())
+    }
 }
 
 impl ::protobuf::Message for Header {
+    const NAME: &'static str = "Header";
+
     fn is_initialized(&self) -> bool {
         if self.signature_scheme.is_none() {
             return false;
@@ -475,37 +514,35 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.signature_scheme, 1, &mut self.unknown_fields)?
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.signature_scheme = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.encryption_scheme, 2, &mut self.unknown_fields)?
+                16 => {
+                    self.encryption_scheme = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                3 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.verification_key_id)?;
+                26 => {
+                    self.verification_key_id = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                4 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.decryption_key_id)?;
+                34 => {
+                    self.decryption_key_id = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                5 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.iv)?;
+                42 => {
+                    self.iv = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                6 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.public_metadata)?;
+                50 => {
+                    self.public_metadata = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                7 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_uint32()?;
-                    self.associated_data_length = ::std::option::Option::Some(tmp);
+                56 => {
+                    self.associated_data_length = ::std::option::Option::Some(is.read_uint32()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                66 => {
+                    self.nonce = ::std::option::Option::Some(is.read_bytes()?);
+                },
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -514,123 +551,117 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.signature_scheme {
-            my_size += ::protobuf::rt::enum_size(1, v);
+            my_size += ::protobuf::rt::int32_size(1, v.value());
         }
         if let Some(v) = self.encryption_scheme {
-            my_size += ::protobuf::rt::enum_size(2, v);
+            my_size += ::protobuf::rt::int32_size(2, v.value());
         }
-        if let Some(ref v) = self.verification_key_id.as_ref() {
+        if let Some(v) = self.verification_key_id.as_ref() {
             my_size += ::protobuf::rt::bytes_size(3, &v);
         }
-        if let Some(ref v) = self.decryption_key_id.as_ref() {
+        if let Some(v) = self.decryption_key_id.as_ref() {
             my_size += ::protobuf::rt::bytes_size(4, &v);
         }
-        if let Some(ref v) = self.iv.as_ref() {
+        if let Some(v) = self.iv.as_ref() {
             my_size += ::protobuf::rt::bytes_size(5, &v);
         }
-        if let Some(ref v) = self.public_metadata.as_ref() {
+        if let Some(v) = self.public_metadata.as_ref() {
             my_size += ::protobuf::rt::bytes_size(6, &v);
         }
         if let Some(v) = self.associated_data_length {
-            my_size += ::protobuf::rt::value_size(7, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::uint32_size(7, v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        if let Some(v) = self.nonce.as_ref() {
+            my_size += ::protobuf::rt::bytes_size(8, &v);
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.signature_scheme {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?;
+            os.write_enum(1, ::protobuf::EnumOrUnknown::value(&v))?;
         }
         if let Some(v) = self.encryption_scheme {
-            os.write_enum(2, ::protobuf::ProtobufEnum::value(&v))?;
+            os.write_enum(2, ::protobuf::EnumOrUnknown::value(&v))?;
         }
-        if let Some(ref v) = self.verification_key_id.as_ref() {
-            os.write_bytes(3, &v)?;
+        if let Some(v) = self.verification_key_id.as_ref() {
+            os.write_bytes(3, v)?;
         }
-        if let Some(ref v) = self.decryption_key_id.as_ref() {
-            os.write_bytes(4, &v)?;
+        if let Some(v) = self.decryption_key_id.as_ref() {
+            os.write_bytes(4, v)?;
         }
-        if let Some(ref v) = self.iv.as_ref() {
-            os.write_bytes(5, &v)?;
+        if let Some(v) = self.iv.as_ref() {
+            os.write_bytes(5, v)?;
         }
-        if let Some(ref v) = self.public_metadata.as_ref() {
-            os.write_bytes(6, &v)?;
+        if let Some(v) = self.public_metadata.as_ref() {
+            os.write_bytes(6, v)?;
         }
         if let Some(v) = self.associated_data_length {
             os.write_uint32(7, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        if let Some(v) = self.nonce.as_ref() {
+            os.write_bytes(8, v)?;
+        }
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> Header {
         Header::new()
     }
 
-    fn default_instance() -> &'static Header {
-        static instance: ::protobuf::rt::LazyV2<Header> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Header::new)
-    }
-}
-
-impl ::protobuf::Clear for Header {
     fn clear(&mut self) {
         self.signature_scheme = ::std::option::Option::None;
         self.encryption_scheme = ::std::option::Option::None;
-        self.verification_key_id.clear();
-        self.decryption_key_id.clear();
-        self.iv.clear();
-        self.public_metadata.clear();
+        self.verification_key_id = ::std::option::Option::None;
+        self.decryption_key_id = ::std::option::Option::None;
+        self.iv = ::std::option::Option::None;
+        self.public_metadata = ::std::option::Option::None;
         self.associated_data_length = ::std::option::Option::None;
-        self.unknown_fields.clear();
+        self.nonce = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for Header {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static Header {
+        static instance: Header = Header {
+            signature_scheme: ::std::option::Option::None,
+            encryption_scheme: ::std::option::Option::None,
+            verification_key_id: ::std::option::Option::None,
+            decryption_key_id: ::std::option::Option::None,
+            iv: ::std::option::Option::None,
+            public_metadata: ::std::option::Option::None,
+            associated_data_length: ::std::option::Option::None,
+            nonce: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.HeaderAndBody)
 pub struct HeaderAndBody {
     // message fields
-    pub header: ::protobuf::SingularPtrField<Header>,
-    body: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.HeaderAndBody.header)
+    pub header: ::protobuf::MessageField<Header>,
+    // @@protoc_insertion_point(field:securemessage.HeaderAndBody.body)
+    pub body: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.HeaderAndBody.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a HeaderAndBody {
@@ -644,50 +675,17 @@
         ::std::default::Default::default()
     }
 
-    // required .securemessage.Header header = 1;
-
-
-    pub fn get_header(&self) -> &Header {
-        self.header.as_ref().unwrap_or_else(|| <Header as ::protobuf::Message>::default_instance())
-    }
-    pub fn clear_header(&mut self) {
-        self.header.clear();
-    }
-
-    pub fn has_header(&self) -> bool {
-        self.header.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_header(&mut self, v: Header) {
-        self.header = ::protobuf::SingularPtrField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_header(&mut self) -> &mut Header {
-        if self.header.is_none() {
-            self.header.set_default();
-        }
-        self.header.as_mut().unwrap()
-    }
-
-    // Take field
-    pub fn take_header(&mut self) -> Header {
-        self.header.take().unwrap_or_else(|| Header::new())
-    }
-
     // required bytes body = 2;
 
-
-    pub fn get_body(&self) -> &[u8] {
+    pub fn body(&self) -> &[u8] {
         match self.body.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_body(&mut self) {
-        self.body.clear();
+        self.body = ::std::option::Option::None;
     }
 
     pub fn has_body(&self) -> bool {
@@ -696,14 +694,14 @@
 
     // Param is passed by value, moved
     pub fn set_body(&mut self, v: ::std::vec::Vec<u8>) {
-        self.body = ::protobuf::SingularField::some(v);
+        self.body = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_body(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.body.is_none() {
-            self.body.set_default();
+            self.body = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.body.as_mut().unwrap()
     }
@@ -715,6 +713,8 @@
 }
 
 impl ::protobuf::Message for HeaderAndBody {
+    const NAME: &'static str = "HeaderAndBody";
+
     fn is_initialized(&self) -> bool {
         if self.header.is_none() {
             return false;
@@ -730,18 +730,17 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.header)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    ::protobuf::rt::read_singular_message_into_field(is, &mut self.header)?;
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.body)?;
+                18 => {
+                    self.body = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -750,91 +749,70 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.header.as_ref() {
+        if let Some(v) = self.header.as_ref() {
             let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         }
-        if let Some(ref v) = self.body.as_ref() {
+        if let Some(v) = self.body.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.header.as_ref() {
-            os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.header.as_ref() {
+            ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?;
         }
-        if let Some(ref v) = self.body.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.body.as_ref() {
+            os.write_bytes(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> HeaderAndBody {
         HeaderAndBody::new()
     }
 
-    fn default_instance() -> &'static HeaderAndBody {
-        static instance: ::protobuf::rt::LazyV2<HeaderAndBody> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(HeaderAndBody::new)
-    }
-}
-
-impl ::protobuf::Clear for HeaderAndBody {
     fn clear(&mut self) {
         self.header.clear();
-        self.body.clear();
-        self.unknown_fields.clear();
+        self.body = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for HeaderAndBody {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static HeaderAndBody {
+        static instance: HeaderAndBody = HeaderAndBody {
+            header: ::protobuf::MessageField::none(),
+            body: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.HeaderAndBodyInternal)
 pub struct HeaderAndBodyInternal {
     // message fields
-    header: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    body: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.HeaderAndBodyInternal.header)
+    pub header: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.HeaderAndBodyInternal.body)
+    pub body: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.HeaderAndBodyInternal.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a HeaderAndBodyInternal {
@@ -850,15 +828,15 @@
 
     // required bytes header = 1;
 
-
-    pub fn get_header(&self) -> &[u8] {
+    pub fn header(&self) -> &[u8] {
         match self.header.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_header(&mut self) {
-        self.header.clear();
+        self.header = ::std::option::Option::None;
     }
 
     pub fn has_header(&self) -> bool {
@@ -867,14 +845,14 @@
 
     // Param is passed by value, moved
     pub fn set_header(&mut self, v: ::std::vec::Vec<u8>) {
-        self.header = ::protobuf::SingularField::some(v);
+        self.header = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_header(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.header.is_none() {
-            self.header.set_default();
+            self.header = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.header.as_mut().unwrap()
     }
@@ -886,15 +864,15 @@
 
     // required bytes body = 2;
 
-
-    pub fn get_body(&self) -> &[u8] {
+    pub fn body(&self) -> &[u8] {
         match self.body.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_body(&mut self) {
-        self.body.clear();
+        self.body = ::std::option::Option::None;
     }
 
     pub fn has_body(&self) -> bool {
@@ -903,14 +881,14 @@
 
     // Param is passed by value, moved
     pub fn set_body(&mut self, v: ::std::vec::Vec<u8>) {
-        self.body = ::protobuf::SingularField::some(v);
+        self.body = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_body(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.body.is_none() {
-            self.body.set_default();
+            self.body = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.body.as_mut().unwrap()
     }
@@ -922,6 +900,8 @@
 }
 
 impl ::protobuf::Message for HeaderAndBodyInternal {
+    const NAME: &'static str = "HeaderAndBodyInternal";
+
     fn is_initialized(&self) -> bool {
         if self.header.is_none() {
             return false;
@@ -932,18 +912,17 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.header)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    self.header = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.body)?;
+                18 => {
+                    self.body = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -952,88 +931,69 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.header.as_ref() {
+        if let Some(v) = self.header.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1, &v);
         }
-        if let Some(ref v) = self.body.as_ref() {
+        if let Some(v) = self.body.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.header.as_ref() {
-            os.write_bytes(1, &v)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.header.as_ref() {
+            os.write_bytes(1, v)?;
         }
-        if let Some(ref v) = self.body.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.body.as_ref() {
+            os.write_bytes(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> HeaderAndBodyInternal {
         HeaderAndBodyInternal::new()
     }
 
-    fn default_instance() -> &'static HeaderAndBodyInternal {
-        static instance: ::protobuf::rt::LazyV2<HeaderAndBodyInternal> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(HeaderAndBodyInternal::new)
-    }
-}
-
-impl ::protobuf::Clear for HeaderAndBodyInternal {
     fn clear(&mut self) {
-        self.header.clear();
-        self.body.clear();
-        self.unknown_fields.clear();
+        self.header = ::std::option::Option::None;
+        self.body = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for HeaderAndBodyInternal {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static HeaderAndBodyInternal {
+        static instance: HeaderAndBodyInternal = HeaderAndBodyInternal {
+            header: ::std::option::Option::None,
+            body: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.EcP256PublicKey)
 pub struct EcP256PublicKey {
     // message fields
-    x: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    y: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.EcP256PublicKey.x)
+    pub x: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.EcP256PublicKey.y)
+    pub y: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.EcP256PublicKey.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a EcP256PublicKey {
@@ -1049,15 +1009,15 @@
 
     // required bytes x = 1;
 
-
-    pub fn get_x(&self) -> &[u8] {
+    pub fn x(&self) -> &[u8] {
         match self.x.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_x(&mut self) {
-        self.x.clear();
+        self.x = ::std::option::Option::None;
     }
 
     pub fn has_x(&self) -> bool {
@@ -1066,14 +1026,14 @@
 
     // Param is passed by value, moved
     pub fn set_x(&mut self, v: ::std::vec::Vec<u8>) {
-        self.x = ::protobuf::SingularField::some(v);
+        self.x = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_x(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.x.is_none() {
-            self.x.set_default();
+            self.x = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.x.as_mut().unwrap()
     }
@@ -1085,15 +1045,15 @@
 
     // required bytes y = 2;
 
-
-    pub fn get_y(&self) -> &[u8] {
+    pub fn y(&self) -> &[u8] {
         match self.y.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_y(&mut self) {
-        self.y.clear();
+        self.y = ::std::option::Option::None;
     }
 
     pub fn has_y(&self) -> bool {
@@ -1102,14 +1062,14 @@
 
     // Param is passed by value, moved
     pub fn set_y(&mut self, v: ::std::vec::Vec<u8>) {
-        self.y = ::protobuf::SingularField::some(v);
+        self.y = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_y(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.y.is_none() {
-            self.y.set_default();
+            self.y = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.y.as_mut().unwrap()
     }
@@ -1121,6 +1081,8 @@
 }
 
 impl ::protobuf::Message for EcP256PublicKey {
+    const NAME: &'static str = "EcP256PublicKey";
+
     fn is_initialized(&self) -> bool {
         if self.x.is_none() {
             return false;
@@ -1131,18 +1093,17 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.x)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    self.x = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.y)?;
+                18 => {
+                    self.y = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1151,88 +1112,69 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.x.as_ref() {
+        if let Some(v) = self.x.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1, &v);
         }
-        if let Some(ref v) = self.y.as_ref() {
+        if let Some(v) = self.y.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.x.as_ref() {
-            os.write_bytes(1, &v)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.x.as_ref() {
+            os.write_bytes(1, v)?;
         }
-        if let Some(ref v) = self.y.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.y.as_ref() {
+            os.write_bytes(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> EcP256PublicKey {
         EcP256PublicKey::new()
     }
 
-    fn default_instance() -> &'static EcP256PublicKey {
-        static instance: ::protobuf::rt::LazyV2<EcP256PublicKey> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(EcP256PublicKey::new)
-    }
-}
-
-impl ::protobuf::Clear for EcP256PublicKey {
     fn clear(&mut self) {
-        self.x.clear();
-        self.y.clear();
-        self.unknown_fields.clear();
+        self.x = ::std::option::Option::None;
+        self.y = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for EcP256PublicKey {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static EcP256PublicKey {
+        static instance: EcP256PublicKey = EcP256PublicKey {
+            x: ::std::option::Option::None,
+            y: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.SimpleRsaPublicKey)
 pub struct SimpleRsaPublicKey {
     // message fields
-    n: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    e: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securemessage.SimpleRsaPublicKey.n)
+    pub n: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.SimpleRsaPublicKey.e)
+    pub e: ::std::option::Option<i32>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.SimpleRsaPublicKey.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a SimpleRsaPublicKey {
@@ -1248,15 +1190,15 @@
 
     // required bytes n = 1;
 
-
-    pub fn get_n(&self) -> &[u8] {
+    pub fn n(&self) -> &[u8] {
         match self.n.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_n(&mut self) {
-        self.n.clear();
+        self.n = ::std::option::Option::None;
     }
 
     pub fn has_n(&self) -> bool {
@@ -1265,14 +1207,14 @@
 
     // Param is passed by value, moved
     pub fn set_n(&mut self, v: ::std::vec::Vec<u8>) {
-        self.n = ::protobuf::SingularField::some(v);
+        self.n = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_n(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.n.is_none() {
-            self.n.set_default();
+            self.n = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.n.as_mut().unwrap()
     }
@@ -1284,10 +1226,10 @@
 
     // optional int32 e = 2;
 
-
-    pub fn get_e(&self) -> i32 {
+    pub fn e(&self) -> i32 {
         self.e.unwrap_or(65537i32)
     }
+
     pub fn clear_e(&mut self) {
         self.e = ::std::option::Option::None;
     }
@@ -1303,6 +1245,8 @@
 }
 
 impl ::protobuf::Message for SimpleRsaPublicKey {
+    const NAME: &'static str = "SimpleRsaPublicKey";
+
     fn is_initialized(&self) -> bool {
         if self.n.is_none() {
             return false;
@@ -1310,22 +1254,17 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.n)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    self.n = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.e = ::std::option::Option::Some(tmp);
+                16 => {
+                    self.e = ::std::option::Option::Some(is.read_int32()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1334,87 +1273,67 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.n.as_ref() {
+        if let Some(v) = self.n.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1, &v);
         }
         if let Some(v) = self.e {
-            my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(2, v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.n.as_ref() {
-            os.write_bytes(1, &v)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.n.as_ref() {
+            os.write_bytes(1, v)?;
         }
         if let Some(v) = self.e {
             os.write_int32(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> SimpleRsaPublicKey {
         SimpleRsaPublicKey::new()
     }
 
-    fn default_instance() -> &'static SimpleRsaPublicKey {
-        static instance: ::protobuf::rt::LazyV2<SimpleRsaPublicKey> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(SimpleRsaPublicKey::new)
-    }
-}
-
-impl ::protobuf::Clear for SimpleRsaPublicKey {
     fn clear(&mut self) {
-        self.n.clear();
+        self.n = ::std::option::Option::None;
         self.e = ::std::option::Option::None;
-        self.unknown_fields.clear();
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for SimpleRsaPublicKey {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static SimpleRsaPublicKey {
+        static instance: SimpleRsaPublicKey = SimpleRsaPublicKey {
+            n: ::std::option::Option::None,
+            e: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.DhPublicKey)
 pub struct DhPublicKey {
     // message fields
-    y: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securemessage.DhPublicKey.y)
+    pub y: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.DhPublicKey.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a DhPublicKey {
@@ -1430,15 +1349,15 @@
 
     // required bytes y = 1;
 
-
-    pub fn get_y(&self) -> &[u8] {
+    pub fn y(&self) -> &[u8] {
         match self.y.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_y(&mut self) {
-        self.y.clear();
+        self.y = ::std::option::Option::None;
     }
 
     pub fn has_y(&self) -> bool {
@@ -1447,14 +1366,14 @@
 
     // Param is passed by value, moved
     pub fn set_y(&mut self, v: ::std::vec::Vec<u8>) {
-        self.y = ::protobuf::SingularField::some(v);
+        self.y = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_y(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.y.is_none() {
-            self.y.set_default();
+            self.y = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.y.as_mut().unwrap()
     }
@@ -1466,6 +1385,8 @@
 }
 
 impl ::protobuf::Message for DhPublicKey {
+    const NAME: &'static str = "DhPublicKey";
+
     fn is_initialized(&self) -> bool {
         if self.y.is_none() {
             return false;
@@ -1473,15 +1394,14 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.y)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    self.y = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1490,83 +1410,65 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.y.as_ref() {
+        if let Some(v) = self.y.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.y.as_ref() {
-            os.write_bytes(1, &v)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.y.as_ref() {
+            os.write_bytes(1, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> DhPublicKey {
         DhPublicKey::new()
     }
 
-    fn default_instance() -> &'static DhPublicKey {
-        static instance: ::protobuf::rt::LazyV2<DhPublicKey> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(DhPublicKey::new)
-    }
-}
-
-impl ::protobuf::Clear for DhPublicKey {
     fn clear(&mut self) {
-        self.y.clear();
-        self.unknown_fields.clear();
+        self.y = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for DhPublicKey {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static DhPublicKey {
+        static instance: DhPublicKey = DhPublicKey {
+            y: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securemessage.GenericPublicKey)
 pub struct GenericPublicKey {
     // message fields
-    field_type: ::std::option::Option<PublicKeyType>,
-    pub ec_p256_public_key: ::protobuf::SingularPtrField<EcP256PublicKey>,
-    pub rsa2048_public_key: ::protobuf::SingularPtrField<SimpleRsaPublicKey>,
-    pub dh2048_public_key: ::protobuf::SingularPtrField<DhPublicKey>,
+    // @@protoc_insertion_point(field:securemessage.GenericPublicKey.type)
+    pub type_: ::std::option::Option<::protobuf::EnumOrUnknown<PublicKeyType>>,
+    // @@protoc_insertion_point(field:securemessage.GenericPublicKey.ec_p256_public_key)
+    pub ec_p256_public_key: ::protobuf::MessageField<EcP256PublicKey>,
+    // @@protoc_insertion_point(field:securemessage.GenericPublicKey.rsa2048_public_key)
+    pub rsa2048_public_key: ::protobuf::MessageField<SimpleRsaPublicKey>,
+    // @@protoc_insertion_point(field:securemessage.GenericPublicKey.dh2048_public_key)
+    pub dh2048_public_key: ::protobuf::MessageField<DhPublicKey>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securemessage.GenericPublicKey.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a GenericPublicKey {
@@ -1582,126 +1484,32 @@
 
     // required .securemessage.PublicKeyType type = 1;
 
-
-    pub fn get_field_type(&self) -> PublicKeyType {
-        self.field_type.unwrap_or(PublicKeyType::EC_P256)
-    }
-    pub fn clear_field_type(&mut self) {
-        self.field_type = ::std::option::Option::None;
-    }
-
-    pub fn has_field_type(&self) -> bool {
-        self.field_type.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_field_type(&mut self, v: PublicKeyType) {
-        self.field_type = ::std::option::Option::Some(v);
-    }
-
-    // optional .securemessage.EcP256PublicKey ec_p256_public_key = 2;
-
-
-    pub fn get_ec_p256_public_key(&self) -> &EcP256PublicKey {
-        self.ec_p256_public_key.as_ref().unwrap_or_else(|| <EcP256PublicKey as ::protobuf::Message>::default_instance())
-    }
-    pub fn clear_ec_p256_public_key(&mut self) {
-        self.ec_p256_public_key.clear();
-    }
-
-    pub fn has_ec_p256_public_key(&self) -> bool {
-        self.ec_p256_public_key.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_ec_p256_public_key(&mut self, v: EcP256PublicKey) {
-        self.ec_p256_public_key = ::protobuf::SingularPtrField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_ec_p256_public_key(&mut self) -> &mut EcP256PublicKey {
-        if self.ec_p256_public_key.is_none() {
-            self.ec_p256_public_key.set_default();
+    pub fn type_(&self) -> PublicKeyType {
+        match self.type_ {
+            Some(e) => e.enum_value_or(PublicKeyType::EC_P256),
+            None => PublicKeyType::EC_P256,
         }
-        self.ec_p256_public_key.as_mut().unwrap()
     }
 
-    // Take field
-    pub fn take_ec_p256_public_key(&mut self) -> EcP256PublicKey {
-        self.ec_p256_public_key.take().unwrap_or_else(|| EcP256PublicKey::new())
+    pub fn clear_type_(&mut self) {
+        self.type_ = ::std::option::Option::None;
     }
 
-    // optional .securemessage.SimpleRsaPublicKey rsa2048_public_key = 3;
-
-
-    pub fn get_rsa2048_public_key(&self) -> &SimpleRsaPublicKey {
-        self.rsa2048_public_key.as_ref().unwrap_or_else(|| <SimpleRsaPublicKey as ::protobuf::Message>::default_instance())
-    }
-    pub fn clear_rsa2048_public_key(&mut self) {
-        self.rsa2048_public_key.clear();
-    }
-
-    pub fn has_rsa2048_public_key(&self) -> bool {
-        self.rsa2048_public_key.is_some()
+    pub fn has_type(&self) -> bool {
+        self.type_.is_some()
     }
 
     // Param is passed by value, moved
-    pub fn set_rsa2048_public_key(&mut self, v: SimpleRsaPublicKey) {
-        self.rsa2048_public_key = ::protobuf::SingularPtrField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_rsa2048_public_key(&mut self) -> &mut SimpleRsaPublicKey {
-        if self.rsa2048_public_key.is_none() {
-            self.rsa2048_public_key.set_default();
-        }
-        self.rsa2048_public_key.as_mut().unwrap()
-    }
-
-    // Take field
-    pub fn take_rsa2048_public_key(&mut self) -> SimpleRsaPublicKey {
-        self.rsa2048_public_key.take().unwrap_or_else(|| SimpleRsaPublicKey::new())
-    }
-
-    // optional .securemessage.DhPublicKey dh2048_public_key = 4;
-
-
-    pub fn get_dh2048_public_key(&self) -> &DhPublicKey {
-        self.dh2048_public_key.as_ref().unwrap_or_else(|| <DhPublicKey as ::protobuf::Message>::default_instance())
-    }
-    pub fn clear_dh2048_public_key(&mut self) {
-        self.dh2048_public_key.clear();
-    }
-
-    pub fn has_dh2048_public_key(&self) -> bool {
-        self.dh2048_public_key.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_dh2048_public_key(&mut self, v: DhPublicKey) {
-        self.dh2048_public_key = ::protobuf::SingularPtrField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_dh2048_public_key(&mut self) -> &mut DhPublicKey {
-        if self.dh2048_public_key.is_none() {
-            self.dh2048_public_key.set_default();
-        }
-        self.dh2048_public_key.as_mut().unwrap()
-    }
-
-    // Take field
-    pub fn take_dh2048_public_key(&mut self) -> DhPublicKey {
-        self.dh2048_public_key.take().unwrap_or_else(|| DhPublicKey::new())
+    pub fn set_type(&mut self, v: PublicKeyType) {
+        self.type_ = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 }
 
 impl ::protobuf::Message for GenericPublicKey {
+    const NAME: &'static str = "GenericPublicKey";
+
     fn is_initialized(&self) -> bool {
-        if self.field_type.is_none() {
+        if self.type_.is_none() {
             return false;
         }
         for v in &self.ec_p256_public_key {
@@ -1722,24 +1530,23 @@
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 1, &mut self.unknown_fields)?
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.type_ = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.ec_p256_public_key)?;
+                18 => {
+                    ::protobuf::rt::read_singular_message_into_field(is, &mut self.ec_p256_public_key)?;
                 },
-                3 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.rsa2048_public_key)?;
+                26 => {
+                    ::protobuf::rt::read_singular_message_into_field(is, &mut self.rsa2048_public_key)?;
                 },
-                4 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.dh2048_public_key)?;
+                34 => {
+                    ::protobuf::rt::read_singular_message_into_field(is, &mut self.dh2048_public_key)?;
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1748,111 +1555,93 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(v) = self.field_type {
-            my_size += ::protobuf::rt::enum_size(1, v);
+        if let Some(v) = self.type_ {
+            my_size += ::protobuf::rt::int32_size(1, v.value());
         }
-        if let Some(ref v) = self.ec_p256_public_key.as_ref() {
+        if let Some(v) = self.ec_p256_public_key.as_ref() {
             let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         }
-        if let Some(ref v) = self.rsa2048_public_key.as_ref() {
+        if let Some(v) = self.rsa2048_public_key.as_ref() {
             let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         }
-        if let Some(ref v) = self.dh2048_public_key.as_ref() {
+        if let Some(v) = self.dh2048_public_key.as_ref() {
             let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(v) = self.field_type {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.type_ {
+            os.write_enum(1, ::protobuf::EnumOrUnknown::value(&v))?;
         }
-        if let Some(ref v) = self.ec_p256_public_key.as_ref() {
-            os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+        if let Some(v) = self.ec_p256_public_key.as_ref() {
+            ::protobuf::rt::write_message_field_with_cached_size(2, v, os)?;
         }
-        if let Some(ref v) = self.rsa2048_public_key.as_ref() {
-            os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+        if let Some(v) = self.rsa2048_public_key.as_ref() {
+            ::protobuf::rt::write_message_field_with_cached_size(3, v, os)?;
         }
-        if let Some(ref v) = self.dh2048_public_key.as_ref() {
-            os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+        if let Some(v) = self.dh2048_public_key.as_ref() {
+            ::protobuf::rt::write_message_field_with_cached_size(4, v, os)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> GenericPublicKey {
         GenericPublicKey::new()
     }
 
-    fn default_instance() -> &'static GenericPublicKey {
-        static instance: ::protobuf::rt::LazyV2<GenericPublicKey> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(GenericPublicKey::new)
-    }
-}
-
-impl ::protobuf::Clear for GenericPublicKey {
     fn clear(&mut self) {
-        self.field_type = ::std::option::Option::None;
+        self.type_ = ::std::option::Option::None;
         self.ec_p256_public_key.clear();
         self.rsa2048_public_key.clear();
         self.dh2048_public_key.clear();
-        self.unknown_fields.clear();
+        self.special_fields.clear();
+    }
+
+    fn default_instance() -> &'static GenericPublicKey {
+        static instance: GenericPublicKey = GenericPublicKey {
+            type_: ::std::option::Option::None,
+            ec_p256_public_key: ::protobuf::MessageField::none(),
+            rsa2048_public_key: ::protobuf::MessageField::none(),
+            dh2048_public_key: ::protobuf::MessageField::none(),
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for GenericPublicKey {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securemessage.SigScheme)
 pub enum SigScheme {
+    // @@protoc_insertion_point(enum_value:securemessage.SigScheme.HMAC_SHA256)
     HMAC_SHA256 = 1,
+    // @@protoc_insertion_point(enum_value:securemessage.SigScheme.ECDSA_P256_SHA256)
     ECDSA_P256_SHA256 = 2,
+    // @@protoc_insertion_point(enum_value:securemessage.SigScheme.RSA2048_SHA256)
     RSA2048_SHA256 = 3,
+    // @@protoc_insertion_point(enum_value:securemessage.SigScheme.AEAD)
+    AEAD = 4,
 }
 
-impl ::protobuf::ProtobufEnum for SigScheme {
+impl ::protobuf::Enum for SigScheme {
+    const NAME: &'static str = "SigScheme";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -1862,21 +1651,17 @@
             1 => ::std::option::Option::Some(SigScheme::HMAC_SHA256),
             2 => ::std::option::Option::Some(SigScheme::ECDSA_P256_SHA256),
             3 => ::std::option::Option::Some(SigScheme::RSA2048_SHA256),
+            4 => ::std::option::Option::Some(SigScheme::AEAD),
             _ => ::std::option::Option::None
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [SigScheme] = &[
-            SigScheme::HMAC_SHA256,
-            SigScheme::ECDSA_P256_SHA256,
-            SigScheme::RSA2048_SHA256,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for SigScheme {
+    const VALUES: &'static [SigScheme] = &[
+        SigScheme::HMAC_SHA256,
+        SigScheme::ECDSA_P256_SHA256,
+        SigScheme::RSA2048_SHA256,
+        SigScheme::AEAD,
+    ];
 }
 
 // Note, `Default` is implemented although default value is not 0
@@ -1886,19 +1671,21 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for SigScheme {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
 
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securemessage.EncScheme)
 pub enum EncScheme {
+    // @@protoc_insertion_point(enum_value:securemessage.EncScheme.NONE)
     NONE = 1,
+    // @@protoc_insertion_point(enum_value:securemessage.EncScheme.AES_256_CBC)
     AES_256_CBC = 2,
+    // @@protoc_insertion_point(enum_value:securemessage.EncScheme.AES_256_GCM_SIV)
+    AES_256_GCM_SIV = 3,
 }
 
-impl ::protobuf::ProtobufEnum for EncScheme {
+impl ::protobuf::Enum for EncScheme {
+    const NAME: &'static str = "EncScheme";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -1907,20 +1694,16 @@
         match value {
             1 => ::std::option::Option::Some(EncScheme::NONE),
             2 => ::std::option::Option::Some(EncScheme::AES_256_CBC),
+            3 => ::std::option::Option::Some(EncScheme::AES_256_GCM_SIV),
             _ => ::std::option::Option::None
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [EncScheme] = &[
-            EncScheme::NONE,
-            EncScheme::AES_256_CBC,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for EncScheme {
+    const VALUES: &'static [EncScheme] = &[
+        EncScheme::NONE,
+        EncScheme::AES_256_CBC,
+        EncScheme::AES_256_GCM_SIV,
+    ];
 }
 
 // Note, `Default` is implemented although default value is not 0
@@ -1930,20 +1713,21 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for EncScheme {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
 
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securemessage.PublicKeyType)
 pub enum PublicKeyType {
+    // @@protoc_insertion_point(enum_value:securemessage.PublicKeyType.EC_P256)
     EC_P256 = 1,
+    // @@protoc_insertion_point(enum_value:securemessage.PublicKeyType.RSA2048)
     RSA2048 = 2,
+    // @@protoc_insertion_point(enum_value:securemessage.PublicKeyType.DH2048_MODP)
     DH2048_MODP = 3,
 }
 
-impl ::protobuf::ProtobufEnum for PublicKeyType {
+impl ::protobuf::Enum for PublicKeyType {
+    const NAME: &'static str = "PublicKeyType";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -1957,17 +1741,11 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [PublicKeyType] = &[
-            PublicKeyType::EC_P256,
-            PublicKeyType::RSA2048,
-            PublicKeyType::DH2048_MODP,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for PublicKeyType {
+    const VALUES: &'static [PublicKeyType] = &[
+        PublicKeyType::EC_P256,
+        PublicKeyType::RSA2048,
+        PublicKeyType::DH2048_MODP,
+    ];
 }
 
 // Note, `Default` is implemented although default value is not 0
@@ -1977,8 +1755,3 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for PublicKeyType {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs
index a4aef70..5370207 100644
--- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs
+++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs
@@ -12,7 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// This file is generated by rust-protobuf 2.28.0. Do not edit
+// This file is generated by rust-protobuf 3.2.0. Do not edit
+// .proto file is parsed by protoc 3.19.1
 // @generated
 
 // https://github.com/rust-lang/rust-clippy/issues/702
@@ -29,22 +30,27 @@
 #![allow(non_snake_case)]
 #![allow(non_upper_case_globals)]
 #![allow(trivial_casts)]
-#![allow(unused_imports)]
 #![allow(unused_results)]
+#![allow(unused_mut)]
+
 //! Generated file from `ukey.proto`
+// Generated for lite runtime
 
 /// Generated files are compatible only with the same version
 /// of protobuf runtime.
-// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_28_0;
+const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.Ukey2Message)
 pub struct Ukey2Message {
     // message fields
-    message_type: ::std::option::Option<Ukey2Message_Type>,
-    message_data: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2Message.message_type)
+    pub message_type: ::std::option::Option<::protobuf::EnumOrUnknown<ukey2message::Type>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2Message.message_data)
+    pub message_data: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.Ukey2Message.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a Ukey2Message {
@@ -60,10 +66,13 @@
 
     // optional .securegcm.Ukey2Message.Type message_type = 1;
 
-
-    pub fn get_message_type(&self) -> Ukey2Message_Type {
-        self.message_type.unwrap_or(Ukey2Message_Type::UNKNOWN_DO_NOT_USE)
+    pub fn message_type(&self) -> ukey2message::Type {
+        match self.message_type {
+            Some(e) => e.enum_value_or(ukey2message::Type::UNKNOWN_DO_NOT_USE),
+            None => ukey2message::Type::UNKNOWN_DO_NOT_USE,
+        }
     }
+
     pub fn clear_message_type(&mut self) {
         self.message_type = ::std::option::Option::None;
     }
@@ -73,21 +82,21 @@
     }
 
     // Param is passed by value, moved
-    pub fn set_message_type(&mut self, v: Ukey2Message_Type) {
-        self.message_type = ::std::option::Option::Some(v);
+    pub fn set_message_type(&mut self, v: ukey2message::Type) {
+        self.message_type = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // optional bytes message_data = 2;
 
-
-    pub fn get_message_data(&self) -> &[u8] {
+    pub fn message_data(&self) -> &[u8] {
         match self.message_data.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_message_data(&mut self) {
-        self.message_data.clear();
+        self.message_data = ::std::option::Option::None;
     }
 
     pub fn has_message_data(&self) -> bool {
@@ -96,14 +105,14 @@
 
     // Param is passed by value, moved
     pub fn set_message_data(&mut self, v: ::std::vec::Vec<u8>) {
-        self.message_data = ::protobuf::SingularField::some(v);
+        self.message_data = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_message_data(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.message_data.is_none() {
-            self.message_data.set_default();
+            self.message_data = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.message_data.as_mut().unwrap()
     }
@@ -115,22 +124,23 @@
 }
 
 impl ::protobuf::Message for Ukey2Message {
+    const NAME: &'static str = "Ukey2Message";
+
     fn is_initialized(&self) -> bool {
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.message_type, 1, &mut self.unknown_fields)?
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.message_type = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.message_data)?;
+                18 => {
+                    self.message_data = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -139,140 +149,121 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.message_type {
-            my_size += ::protobuf::rt::enum_size(1, v);
+            my_size += ::protobuf::rt::int32_size(1, v.value());
         }
-        if let Some(ref v) = self.message_data.as_ref() {
+        if let Some(v) = self.message_data.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.message_type {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?;
+            os.write_enum(1, ::protobuf::EnumOrUnknown::value(&v))?;
         }
-        if let Some(ref v) = self.message_data.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.message_data.as_ref() {
+            os.write_bytes(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> Ukey2Message {
         Ukey2Message::new()
     }
 
-    fn default_instance() -> &'static Ukey2Message {
-        static instance: ::protobuf::rt::LazyV2<Ukey2Message> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Ukey2Message::new)
-    }
-}
-
-impl ::protobuf::Clear for Ukey2Message {
     fn clear(&mut self) {
         self.message_type = ::std::option::Option::None;
-        self.message_data.clear();
-        self.unknown_fields.clear();
+        self.message_data = ::std::option::Option::None;
+        self.special_fields.clear();
+    }
+
+    fn default_instance() -> &'static Ukey2Message {
+        static instance: Ukey2Message = Ukey2Message {
+            message_type: ::std::option::Option::None,
+            message_data: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for Ukey2Message {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum Ukey2Message_Type {
-    UNKNOWN_DO_NOT_USE = 0,
-    ALERT = 1,
-    CLIENT_INIT = 2,
-    SERVER_INIT = 3,
-    CLIENT_FINISH = 4,
-}
-
-impl ::protobuf::ProtobufEnum for Ukey2Message_Type {
-    fn value(&self) -> i32 {
-        *self as i32
+/// Nested message and enums of message `Ukey2Message`
+pub mod ukey2message {
+    #[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+    // @@protoc_insertion_point(enum:securegcm.Ukey2Message.Type)
+    pub enum Type {
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Message.Type.UNKNOWN_DO_NOT_USE)
+        UNKNOWN_DO_NOT_USE = 0,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Message.Type.ALERT)
+        ALERT = 1,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Message.Type.CLIENT_INIT)
+        CLIENT_INIT = 2,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Message.Type.SERVER_INIT)
+        SERVER_INIT = 3,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Message.Type.CLIENT_FINISH)
+        CLIENT_FINISH = 4,
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<Ukey2Message_Type> {
-        match value {
-            0 => ::std::option::Option::Some(Ukey2Message_Type::UNKNOWN_DO_NOT_USE),
-            1 => ::std::option::Option::Some(Ukey2Message_Type::ALERT),
-            2 => ::std::option::Option::Some(Ukey2Message_Type::CLIENT_INIT),
-            3 => ::std::option::Option::Some(Ukey2Message_Type::SERVER_INIT),
-            4 => ::std::option::Option::Some(Ukey2Message_Type::CLIENT_FINISH),
-            _ => ::std::option::Option::None
+    impl ::protobuf::Enum for Type {
+        const NAME: &'static str = "Type";
+
+        fn value(&self) -> i32 {
+            *self as i32
+        }
+
+        fn from_i32(value: i32) -> ::std::option::Option<Type> {
+            match value {
+                0 => ::std::option::Option::Some(Type::UNKNOWN_DO_NOT_USE),
+                1 => ::std::option::Option::Some(Type::ALERT),
+                2 => ::std::option::Option::Some(Type::CLIENT_INIT),
+                3 => ::std::option::Option::Some(Type::SERVER_INIT),
+                4 => ::std::option::Option::Some(Type::CLIENT_FINISH),
+                _ => ::std::option::Option::None
+            }
+        }
+
+        const VALUES: &'static [Type] = &[
+            Type::UNKNOWN_DO_NOT_USE,
+            Type::ALERT,
+            Type::CLIENT_INIT,
+            Type::SERVER_INIT,
+            Type::CLIENT_FINISH,
+        ];
+    }
+
+    impl ::std::default::Default for Type {
+        fn default() -> Self {
+            Type::UNKNOWN_DO_NOT_USE
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [Ukey2Message_Type] = &[
-            Ukey2Message_Type::UNKNOWN_DO_NOT_USE,
-            Ukey2Message_Type::ALERT,
-            Ukey2Message_Type::CLIENT_INIT,
-            Ukey2Message_Type::SERVER_INIT,
-            Ukey2Message_Type::CLIENT_FINISH,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for Ukey2Message_Type {
-}
-
-impl ::std::default::Default for Ukey2Message_Type {
-    fn default() -> Self {
-        Ukey2Message_Type::UNKNOWN_DO_NOT_USE
-    }
-}
-
-impl ::protobuf::reflect::ProtobufValue for Ukey2Message_Type {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.Ukey2Alert)
 pub struct Ukey2Alert {
     // message fields
-    field_type: ::std::option::Option<Ukey2Alert_AlertType>,
-    error_message: ::protobuf::SingularField<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2Alert.type)
+    pub type_: ::std::option::Option<::protobuf::EnumOrUnknown<ukey2alert::AlertType>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2Alert.error_message)
+    pub error_message: ::std::option::Option<::std::string::String>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.Ukey2Alert.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a Ukey2Alert {
@@ -288,34 +279,37 @@
 
     // optional .securegcm.Ukey2Alert.AlertType type = 1;
 
-
-    pub fn get_field_type(&self) -> Ukey2Alert_AlertType {
-        self.field_type.unwrap_or(Ukey2Alert_AlertType::BAD_MESSAGE)
-    }
-    pub fn clear_field_type(&mut self) {
-        self.field_type = ::std::option::Option::None;
+    pub fn type_(&self) -> ukey2alert::AlertType {
+        match self.type_ {
+            Some(e) => e.enum_value_or(ukey2alert::AlertType::BAD_MESSAGE),
+            None => ukey2alert::AlertType::BAD_MESSAGE,
+        }
     }
 
-    pub fn has_field_type(&self) -> bool {
-        self.field_type.is_some()
+    pub fn clear_type_(&mut self) {
+        self.type_ = ::std::option::Option::None;
+    }
+
+    pub fn has_type(&self) -> bool {
+        self.type_.is_some()
     }
 
     // Param is passed by value, moved
-    pub fn set_field_type(&mut self, v: Ukey2Alert_AlertType) {
-        self.field_type = ::std::option::Option::Some(v);
+    pub fn set_type(&mut self, v: ukey2alert::AlertType) {
+        self.type_ = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // optional string error_message = 2;
 
-
-    pub fn get_error_message(&self) -> &str {
+    pub fn error_message(&self) -> &str {
         match self.error_message.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_error_message(&mut self) {
-        self.error_message.clear();
+        self.error_message = ::std::option::Option::None;
     }
 
     pub fn has_error_message(&self) -> bool {
@@ -324,14 +318,14 @@
 
     // Param is passed by value, moved
     pub fn set_error_message(&mut self, v: ::std::string::String) {
-        self.error_message = ::protobuf::SingularField::some(v);
+        self.error_message = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_error_message(&mut self) -> &mut ::std::string::String {
         if self.error_message.is_none() {
-            self.error_message.set_default();
+            self.error_message = ::std::option::Option::Some(::std::string::String::new());
         }
         self.error_message.as_mut().unwrap()
     }
@@ -343,22 +337,23 @@
 }
 
 impl ::protobuf::Message for Ukey2Alert {
+    const NAME: &'static str = "Ukey2Alert";
+
     fn is_initialized(&self) -> bool {
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 1, &mut self.unknown_fields)?
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.type_ = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.error_message)?;
+                18 => {
+                    self.error_message = ::std::option::Option::Some(is.read_string()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -367,158 +362,148 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(v) = self.field_type {
-            my_size += ::protobuf::rt::enum_size(1, v);
+        if let Some(v) = self.type_ {
+            my_size += ::protobuf::rt::int32_size(1, v.value());
         }
-        if let Some(ref v) = self.error_message.as_ref() {
+        if let Some(v) = self.error_message.as_ref() {
             my_size += ::protobuf::rt::string_size(2, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(v) = self.field_type {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.type_ {
+            os.write_enum(1, ::protobuf::EnumOrUnknown::value(&v))?;
         }
-        if let Some(ref v) = self.error_message.as_ref() {
-            os.write_string(2, &v)?;
+        if let Some(v) = self.error_message.as_ref() {
+            os.write_string(2, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> Ukey2Alert {
         Ukey2Alert::new()
     }
 
-    fn default_instance() -> &'static Ukey2Alert {
-        static instance: ::protobuf::rt::LazyV2<Ukey2Alert> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Ukey2Alert::new)
-    }
-}
-
-impl ::protobuf::Clear for Ukey2Alert {
     fn clear(&mut self) {
-        self.field_type = ::std::option::Option::None;
-        self.error_message.clear();
-        self.unknown_fields.clear();
+        self.type_ = ::std::option::Option::None;
+        self.error_message = ::std::option::Option::None;
+        self.special_fields.clear();
+    }
+
+    fn default_instance() -> &'static Ukey2Alert {
+        static instance: Ukey2Alert = Ukey2Alert {
+            type_: ::std::option::Option::None,
+            error_message: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for Ukey2Alert {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum Ukey2Alert_AlertType {
-    BAD_MESSAGE = 1,
-    BAD_MESSAGE_TYPE = 2,
-    INCORRECT_MESSAGE = 3,
-    BAD_MESSAGE_DATA = 4,
-    BAD_VERSION = 100,
-    BAD_RANDOM = 101,
-    BAD_HANDSHAKE_CIPHER = 102,
-    BAD_NEXT_PROTOCOL = 103,
-    BAD_PUBLIC_KEY = 104,
-    INTERNAL_ERROR = 200,
-}
-
-impl ::protobuf::ProtobufEnum for Ukey2Alert_AlertType {
-    fn value(&self) -> i32 {
-        *self as i32
+/// Nested message and enums of message `Ukey2Alert`
+pub mod ukey2alert {
+    #[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+    // @@protoc_insertion_point(enum:securegcm.Ukey2Alert.AlertType)
+    pub enum AlertType {
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_MESSAGE)
+        BAD_MESSAGE = 1,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_MESSAGE_TYPE)
+        BAD_MESSAGE_TYPE = 2,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.INCORRECT_MESSAGE)
+        INCORRECT_MESSAGE = 3,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_MESSAGE_DATA)
+        BAD_MESSAGE_DATA = 4,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_VERSION)
+        BAD_VERSION = 100,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_RANDOM)
+        BAD_RANDOM = 101,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_HANDSHAKE_CIPHER)
+        BAD_HANDSHAKE_CIPHER = 102,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_NEXT_PROTOCOL)
+        BAD_NEXT_PROTOCOL = 103,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.BAD_PUBLIC_KEY)
+        BAD_PUBLIC_KEY = 104,
+        // @@protoc_insertion_point(enum_value:securegcm.Ukey2Alert.AlertType.INTERNAL_ERROR)
+        INTERNAL_ERROR = 200,
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<Ukey2Alert_AlertType> {
-        match value {
-            1 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_MESSAGE),
-            2 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_MESSAGE_TYPE),
-            3 => ::std::option::Option::Some(Ukey2Alert_AlertType::INCORRECT_MESSAGE),
-            4 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_MESSAGE_DATA),
-            100 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_VERSION),
-            101 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_RANDOM),
-            102 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_HANDSHAKE_CIPHER),
-            103 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_NEXT_PROTOCOL),
-            104 => ::std::option::Option::Some(Ukey2Alert_AlertType::BAD_PUBLIC_KEY),
-            200 => ::std::option::Option::Some(Ukey2Alert_AlertType::INTERNAL_ERROR),
-            _ => ::std::option::Option::None
+    impl ::protobuf::Enum for AlertType {
+        const NAME: &'static str = "AlertType";
+
+        fn value(&self) -> i32 {
+            *self as i32
+        }
+
+        fn from_i32(value: i32) -> ::std::option::Option<AlertType> {
+            match value {
+                1 => ::std::option::Option::Some(AlertType::BAD_MESSAGE),
+                2 => ::std::option::Option::Some(AlertType::BAD_MESSAGE_TYPE),
+                3 => ::std::option::Option::Some(AlertType::INCORRECT_MESSAGE),
+                4 => ::std::option::Option::Some(AlertType::BAD_MESSAGE_DATA),
+                100 => ::std::option::Option::Some(AlertType::BAD_VERSION),
+                101 => ::std::option::Option::Some(AlertType::BAD_RANDOM),
+                102 => ::std::option::Option::Some(AlertType::BAD_HANDSHAKE_CIPHER),
+                103 => ::std::option::Option::Some(AlertType::BAD_NEXT_PROTOCOL),
+                104 => ::std::option::Option::Some(AlertType::BAD_PUBLIC_KEY),
+                200 => ::std::option::Option::Some(AlertType::INTERNAL_ERROR),
+                _ => ::std::option::Option::None
+            }
+        }
+
+        const VALUES: &'static [AlertType] = &[
+            AlertType::BAD_MESSAGE,
+            AlertType::BAD_MESSAGE_TYPE,
+            AlertType::INCORRECT_MESSAGE,
+            AlertType::BAD_MESSAGE_DATA,
+            AlertType::BAD_VERSION,
+            AlertType::BAD_RANDOM,
+            AlertType::BAD_HANDSHAKE_CIPHER,
+            AlertType::BAD_NEXT_PROTOCOL,
+            AlertType::BAD_PUBLIC_KEY,
+            AlertType::INTERNAL_ERROR,
+        ];
+    }
+
+    // Note, `Default` is implemented although default value is not 0
+    impl ::std::default::Default for AlertType {
+        fn default() -> Self {
+            AlertType::BAD_MESSAGE
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [Ukey2Alert_AlertType] = &[
-            Ukey2Alert_AlertType::BAD_MESSAGE,
-            Ukey2Alert_AlertType::BAD_MESSAGE_TYPE,
-            Ukey2Alert_AlertType::INCORRECT_MESSAGE,
-            Ukey2Alert_AlertType::BAD_MESSAGE_DATA,
-            Ukey2Alert_AlertType::BAD_VERSION,
-            Ukey2Alert_AlertType::BAD_RANDOM,
-            Ukey2Alert_AlertType::BAD_HANDSHAKE_CIPHER,
-            Ukey2Alert_AlertType::BAD_NEXT_PROTOCOL,
-            Ukey2Alert_AlertType::BAD_PUBLIC_KEY,
-            Ukey2Alert_AlertType::INTERNAL_ERROR,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for Ukey2Alert_AlertType {
-}
-
-// Note, `Default` is implemented although default value is not 0
-impl ::std::default::Default for Ukey2Alert_AlertType {
-    fn default() -> Self {
-        Ukey2Alert_AlertType::BAD_MESSAGE
-    }
-}
-
-impl ::protobuf::reflect::ProtobufValue for Ukey2Alert_AlertType {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.Ukey2ClientInit)
 pub struct Ukey2ClientInit {
     // message fields
-    version: ::std::option::Option<i32>,
-    random: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    pub cipher_commitments: ::protobuf::RepeatedField<Ukey2ClientInit_CipherCommitment>,
-    next_protocol: ::protobuf::SingularField<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.version)
+    pub version: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.random)
+    pub random: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.cipher_commitments)
+    pub cipher_commitments: ::std::vec::Vec<ukey2client_init::CipherCommitment>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.next_protocol)
+    pub next_protocol: ::std::option::Option<::std::string::String>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.other_next_protocols)
+    pub other_next_protocols: ::std::vec::Vec<::std::string::String>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.Ukey2ClientInit.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a Ukey2ClientInit {
@@ -534,10 +519,10 @@
 
     // optional int32 version = 1;
 
-
-    pub fn get_version(&self) -> i32 {
+    pub fn version(&self) -> i32 {
         self.version.unwrap_or(0)
     }
+
     pub fn clear_version(&mut self) {
         self.version = ::std::option::Option::None;
     }
@@ -553,15 +538,15 @@
 
     // optional bytes random = 2;
 
-
-    pub fn get_random(&self) -> &[u8] {
+    pub fn random(&self) -> &[u8] {
         match self.random.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_random(&mut self) {
-        self.random.clear();
+        self.random = ::std::option::Option::None;
     }
 
     pub fn has_random(&self) -> bool {
@@ -570,14 +555,14 @@
 
     // Param is passed by value, moved
     pub fn set_random(&mut self, v: ::std::vec::Vec<u8>) {
-        self.random = ::protobuf::SingularField::some(v);
+        self.random = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_random(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.random.is_none() {
-            self.random.set_default();
+            self.random = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.random.as_mut().unwrap()
     }
@@ -587,42 +572,17 @@
         self.random.take().unwrap_or_else(|| ::std::vec::Vec::new())
     }
 
-    // repeated .securegcm.Ukey2ClientInit.CipherCommitment cipher_commitments = 3;
-
-
-    pub fn get_cipher_commitments(&self) -> &[Ukey2ClientInit_CipherCommitment] {
-        &self.cipher_commitments
-    }
-    pub fn clear_cipher_commitments(&mut self) {
-        self.cipher_commitments.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_cipher_commitments(&mut self, v: ::protobuf::RepeatedField<Ukey2ClientInit_CipherCommitment>) {
-        self.cipher_commitments = v;
-    }
-
-    // Mutable pointer to the field.
-    pub fn mut_cipher_commitments(&mut self) -> &mut ::protobuf::RepeatedField<Ukey2ClientInit_CipherCommitment> {
-        &mut self.cipher_commitments
-    }
-
-    // Take field
-    pub fn take_cipher_commitments(&mut self) -> ::protobuf::RepeatedField<Ukey2ClientInit_CipherCommitment> {
-        ::std::mem::replace(&mut self.cipher_commitments, ::protobuf::RepeatedField::new())
-    }
-
     // optional string next_protocol = 4;
 
-
-    pub fn get_next_protocol(&self) -> &str {
+    pub fn next_protocol(&self) -> &str {
         match self.next_protocol.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => "",
         }
     }
+
     pub fn clear_next_protocol(&mut self) {
-        self.next_protocol.clear();
+        self.next_protocol = ::std::option::Option::None;
     }
 
     pub fn has_next_protocol(&self) -> bool {
@@ -631,14 +591,14 @@
 
     // Param is passed by value, moved
     pub fn set_next_protocol(&mut self, v: ::std::string::String) {
-        self.next_protocol = ::protobuf::SingularField::some(v);
+        self.next_protocol = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_next_protocol(&mut self) -> &mut ::std::string::String {
         if self.next_protocol.is_none() {
-            self.next_protocol.set_default();
+            self.next_protocol = ::std::option::Option::Some(::std::string::String::new());
         }
         self.next_protocol.as_mut().unwrap()
     }
@@ -650,37 +610,32 @@
 }
 
 impl ::protobuf::Message for Ukey2ClientInit {
+    const NAME: &'static str = "Ukey2ClientInit";
+
     fn is_initialized(&self) -> bool {
-        for v in &self.cipher_commitments {
-            if !v.is_initialized() {
-                return false;
-            }
-        };
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.version = ::std::option::Option::Some(tmp);
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.version = ::std::option::Option::Some(is.read_int32()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.random)?;
+                18 => {
+                    self.random = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                3 => {
-                    ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.cipher_commitments)?;
+                26 => {
+                    self.cipher_commitments.push(is.read_message()?);
                 },
-                4 => {
-                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.next_protocol)?;
+                34 => {
+                    self.next_protocol = ::std::option::Option::Some(is.read_string()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                42 => {
+                    self.other_next_protocols.push(is.read_string()?);
+                },
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -689,283 +644,264 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.version {
-            my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(1, v);
         }
-        if let Some(ref v) = self.random.as_ref() {
+        if let Some(v) = self.random.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
         for value in &self.cipher_commitments {
             let len = value.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
         };
-        if let Some(ref v) = self.next_protocol.as_ref() {
+        if let Some(v) = self.next_protocol.as_ref() {
             my_size += ::protobuf::rt::string_size(4, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        for value in &self.other_next_protocols {
+            my_size += ::protobuf::rt::string_size(5, &value);
+        };
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.version {
             os.write_int32(1, v)?;
         }
-        if let Some(ref v) = self.random.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.random.as_ref() {
+            os.write_bytes(2, v)?;
         }
         for v in &self.cipher_commitments {
-            os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+            ::protobuf::rt::write_message_field_with_cached_size(3, v, os)?;
         };
-        if let Some(ref v) = self.next_protocol.as_ref() {
-            os.write_string(4, &v)?;
+        if let Some(v) = self.next_protocol.as_ref() {
+            os.write_string(4, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        for v in &self.other_next_protocols {
+            os.write_string(5, &v)?;
+        };
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> Ukey2ClientInit {
         Ukey2ClientInit::new()
     }
 
-    fn default_instance() -> &'static Ukey2ClientInit {
-        static instance: ::protobuf::rt::LazyV2<Ukey2ClientInit> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Ukey2ClientInit::new)
-    }
-}
-
-impl ::protobuf::Clear for Ukey2ClientInit {
     fn clear(&mut self) {
         self.version = ::std::option::Option::None;
-        self.random.clear();
+        self.random = ::std::option::Option::None;
         self.cipher_commitments.clear();
-        self.next_protocol.clear();
-        self.unknown_fields.clear();
+        self.next_protocol = ::std::option::Option::None;
+        self.other_next_protocols.clear();
+        self.special_fields.clear();
+    }
+
+    fn default_instance() -> &'static Ukey2ClientInit {
+        static instance: Ukey2ClientInit = Ukey2ClientInit {
+            version: ::std::option::Option::None,
+            random: ::std::option::Option::None,
+            cipher_commitments: ::std::vec::Vec::new(),
+            next_protocol: ::std::option::Option::None,
+            other_next_protocols: ::std::vec::Vec::new(),
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for Ukey2ClientInit {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
-#[derive(PartialEq,Clone,Default,Debug)]
-pub struct Ukey2ClientInit_CipherCommitment {
-    // message fields
-    handshake_cipher: ::std::option::Option<Ukey2HandshakeCipher>,
-    commitment: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
-}
-
-impl<'a> ::std::default::Default for &'a Ukey2ClientInit_CipherCommitment {
-    fn default() -> &'a Ukey2ClientInit_CipherCommitment {
-        <Ukey2ClientInit_CipherCommitment as ::protobuf::Message>::default_instance()
-    }
-}
-
-impl Ukey2ClientInit_CipherCommitment {
-    pub fn new() -> Ukey2ClientInit_CipherCommitment {
-        ::std::default::Default::default()
+/// Nested message and enums of message `Ukey2ClientInit`
+pub mod ukey2client_init {
+    #[derive(PartialEq,Clone,Default,Debug)]
+    // @@protoc_insertion_point(message:securegcm.Ukey2ClientInit.CipherCommitment)
+    pub struct CipherCommitment {
+        // message fields
+        // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.CipherCommitment.handshake_cipher)
+        pub handshake_cipher: ::std::option::Option<::protobuf::EnumOrUnknown<super::Ukey2HandshakeCipher>>,
+        // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.CipherCommitment.commitment)
+        pub commitment: ::std::option::Option<::std::vec::Vec<u8>>,
+        // special fields
+        // @@protoc_insertion_point(special_field:securegcm.Ukey2ClientInit.CipherCommitment.special_fields)
+        pub special_fields: ::protobuf::SpecialFields,
     }
 
-    // optional .securegcm.Ukey2HandshakeCipher handshake_cipher = 1;
-
-
-    pub fn get_handshake_cipher(&self) -> Ukey2HandshakeCipher {
-        self.handshake_cipher.unwrap_or(Ukey2HandshakeCipher::RESERVED)
-    }
-    pub fn clear_handshake_cipher(&mut self) {
-        self.handshake_cipher = ::std::option::Option::None;
-    }
-
-    pub fn has_handshake_cipher(&self) -> bool {
-        self.handshake_cipher.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_handshake_cipher(&mut self, v: Ukey2HandshakeCipher) {
-        self.handshake_cipher = ::std::option::Option::Some(v);
-    }
-
-    // optional bytes commitment = 2;
-
-
-    pub fn get_commitment(&self) -> &[u8] {
-        match self.commitment.as_ref() {
-            Some(v) => &v,
-            None => &[],
+    impl<'a> ::std::default::Default for &'a CipherCommitment {
+        fn default() -> &'a CipherCommitment {
+            <CipherCommitment as ::protobuf::Message>::default_instance()
         }
     }
-    pub fn clear_commitment(&mut self) {
-        self.commitment.clear();
-    }
 
-    pub fn has_commitment(&self) -> bool {
-        self.commitment.is_some()
-    }
-
-    // Param is passed by value, moved
-    pub fn set_commitment(&mut self, v: ::std::vec::Vec<u8>) {
-        self.commitment = ::protobuf::SingularField::some(v);
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_commitment(&mut self) -> &mut ::std::vec::Vec<u8> {
-        if self.commitment.is_none() {
-            self.commitment.set_default();
+    impl CipherCommitment {
+        pub fn new() -> CipherCommitment {
+            ::std::default::Default::default()
         }
-        self.commitment.as_mut().unwrap()
+
+        // optional .securegcm.Ukey2HandshakeCipher handshake_cipher = 1;
+
+        pub fn handshake_cipher(&self) -> super::Ukey2HandshakeCipher {
+            match self.handshake_cipher {
+                Some(e) => e.enum_value_or(super::Ukey2HandshakeCipher::RESERVED),
+                None => super::Ukey2HandshakeCipher::RESERVED,
+            }
+        }
+
+        pub fn clear_handshake_cipher(&mut self) {
+            self.handshake_cipher = ::std::option::Option::None;
+        }
+
+        pub fn has_handshake_cipher(&self) -> bool {
+            self.handshake_cipher.is_some()
+        }
+
+        // Param is passed by value, moved
+        pub fn set_handshake_cipher(&mut self, v: super::Ukey2HandshakeCipher) {
+            self.handshake_cipher = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
+        }
+
+        // optional bytes commitment = 2;
+
+        pub fn commitment(&self) -> &[u8] {
+            match self.commitment.as_ref() {
+                Some(v) => v,
+                None => &[],
+            }
+        }
+
+        pub fn clear_commitment(&mut self) {
+            self.commitment = ::std::option::Option::None;
+        }
+
+        pub fn has_commitment(&self) -> bool {
+            self.commitment.is_some()
+        }
+
+        // Param is passed by value, moved
+        pub fn set_commitment(&mut self, v: ::std::vec::Vec<u8>) {
+            self.commitment = ::std::option::Option::Some(v);
+        }
+
+        // Mutable pointer to the field.
+        // If field is not initialized, it is initialized with default value first.
+        pub fn mut_commitment(&mut self) -> &mut ::std::vec::Vec<u8> {
+            if self.commitment.is_none() {
+                self.commitment = ::std::option::Option::Some(::std::vec::Vec::new());
+            }
+            self.commitment.as_mut().unwrap()
+        }
+
+        // Take field
+        pub fn take_commitment(&mut self) -> ::std::vec::Vec<u8> {
+            self.commitment.take().unwrap_or_else(|| ::std::vec::Vec::new())
+        }
     }
 
-    // Take field
-    pub fn take_commitment(&mut self) -> ::std::vec::Vec<u8> {
-        self.commitment.take().unwrap_or_else(|| ::std::vec::Vec::new())
-    }
-}
+    impl ::protobuf::Message for CipherCommitment {
+        const NAME: &'static str = "CipherCommitment";
 
-impl ::protobuf::Message for Ukey2ClientInit_CipherCommitment {
-    fn is_initialized(&self) -> bool {
-        true
-    }
+        fn is_initialized(&self) -> bool {
+            true
+        }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.handshake_cipher, 1, &mut self.unknown_fields)?
-                },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.commitment)?;
-                },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
-                },
+        fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+            while let Some(tag) = is.read_raw_tag_or_eof()? {
+                match tag {
+                    8 => {
+                        self.handshake_cipher = ::std::option::Option::Some(is.read_enum_or_unknown()?);
+                    },
+                    18 => {
+                        self.commitment = ::std::option::Option::Some(is.read_bytes()?);
+                    },
+                    tag => {
+                        ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
+                    },
+                };
+            }
+            ::std::result::Result::Ok(())
+        }
+
+        // Compute sizes of nested messages
+        #[allow(unused_variables)]
+        fn compute_size(&self) -> u64 {
+            let mut my_size = 0;
+            if let Some(v) = self.handshake_cipher {
+                my_size += ::protobuf::rt::int32_size(1, v.value());
+            }
+            if let Some(v) = self.commitment.as_ref() {
+                my_size += ::protobuf::rt::bytes_size(2, &v);
+            }
+            my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+            self.special_fields.cached_size().set(my_size as u32);
+            my_size
+        }
+
+        fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+            if let Some(v) = self.handshake_cipher {
+                os.write_enum(1, ::protobuf::EnumOrUnknown::value(&v))?;
+            }
+            if let Some(v) = self.commitment.as_ref() {
+                os.write_bytes(2, v)?;
+            }
+            os.write_unknown_fields(self.special_fields.unknown_fields())?;
+            ::std::result::Result::Ok(())
+        }
+
+        fn special_fields(&self) -> &::protobuf::SpecialFields {
+            &self.special_fields
+        }
+
+        fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+            &mut self.special_fields
+        }
+
+        fn new() -> CipherCommitment {
+            CipherCommitment::new()
+        }
+
+        fn clear(&mut self) {
+            self.handshake_cipher = ::std::option::Option::None;
+            self.commitment = ::std::option::Option::None;
+            self.special_fields.clear();
+        }
+
+        fn default_instance() -> &'static CipherCommitment {
+            static instance: CipherCommitment = CipherCommitment {
+                handshake_cipher: ::std::option::Option::None,
+                commitment: ::std::option::Option::None,
+                special_fields: ::protobuf::SpecialFields::new(),
             };
+            &instance
         }
-        ::std::result::Result::Ok(())
-    }
-
-    // Compute sizes of nested messages
-    #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
-        let mut my_size = 0;
-        if let Some(v) = self.handshake_cipher {
-            my_size += ::protobuf::rt::enum_size(1, v);
-        }
-        if let Some(ref v) = self.commitment.as_ref() {
-            my_size += ::protobuf::rt::bytes_size(2, &v);
-        }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
-        my_size
-    }
-
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(v) = self.handshake_cipher {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&v))?;
-        }
-        if let Some(ref v) = self.commitment.as_ref() {
-            os.write_bytes(2, &v)?;
-        }
-        os.write_unknown_fields(self.get_unknown_fields())?;
-        ::std::result::Result::Ok(())
-    }
-
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
-    }
-
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
-    }
-
-    fn new() -> Ukey2ClientInit_CipherCommitment {
-        Ukey2ClientInit_CipherCommitment::new()
-    }
-
-    fn default_instance() -> &'static Ukey2ClientInit_CipherCommitment {
-        static instance: ::protobuf::rt::LazyV2<Ukey2ClientInit_CipherCommitment> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Ukey2ClientInit_CipherCommitment::new)
-    }
-}
-
-impl ::protobuf::Clear for Ukey2ClientInit_CipherCommitment {
-    fn clear(&mut self) {
-        self.handshake_cipher = ::std::option::Option::None;
-        self.commitment.clear();
-        self.unknown_fields.clear();
-    }
-}
-
-impl ::protobuf::reflect::ProtobufValue for Ukey2ClientInit_CipherCommitment {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.Ukey2ServerInit)
 pub struct Ukey2ServerInit {
     // message fields
-    version: ::std::option::Option<i32>,
-    random: ::protobuf::SingularField<::std::vec::Vec<u8>>,
-    handshake_cipher: ::std::option::Option<Ukey2HandshakeCipher>,
-    public_key: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ServerInit.version)
+    pub version: ::std::option::Option<i32>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ServerInit.random)
+    pub random: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ServerInit.handshake_cipher)
+    pub handshake_cipher: ::std::option::Option<::protobuf::EnumOrUnknown<Ukey2HandshakeCipher>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ServerInit.public_key)
+    pub public_key: ::std::option::Option<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ServerInit.selected_next_protocol)
+    pub selected_next_protocol: ::std::option::Option<::std::string::String>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.Ukey2ServerInit.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a Ukey2ServerInit {
@@ -981,10 +917,10 @@
 
     // optional int32 version = 1;
 
-
-    pub fn get_version(&self) -> i32 {
+    pub fn version(&self) -> i32 {
         self.version.unwrap_or(0)
     }
+
     pub fn clear_version(&mut self) {
         self.version = ::std::option::Option::None;
     }
@@ -1000,15 +936,15 @@
 
     // optional bytes random = 2;
 
-
-    pub fn get_random(&self) -> &[u8] {
+    pub fn random(&self) -> &[u8] {
         match self.random.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_random(&mut self) {
-        self.random.clear();
+        self.random = ::std::option::Option::None;
     }
 
     pub fn has_random(&self) -> bool {
@@ -1017,14 +953,14 @@
 
     // Param is passed by value, moved
     pub fn set_random(&mut self, v: ::std::vec::Vec<u8>) {
-        self.random = ::protobuf::SingularField::some(v);
+        self.random = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_random(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.random.is_none() {
-            self.random.set_default();
+            self.random = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.random.as_mut().unwrap()
     }
@@ -1036,10 +972,13 @@
 
     // optional .securegcm.Ukey2HandshakeCipher handshake_cipher = 3;
 
-
-    pub fn get_handshake_cipher(&self) -> Ukey2HandshakeCipher {
-        self.handshake_cipher.unwrap_or(Ukey2HandshakeCipher::RESERVED)
+    pub fn handshake_cipher(&self) -> Ukey2HandshakeCipher {
+        match self.handshake_cipher {
+            Some(e) => e.enum_value_or(Ukey2HandshakeCipher::RESERVED),
+            None => Ukey2HandshakeCipher::RESERVED,
+        }
     }
+
     pub fn clear_handshake_cipher(&mut self) {
         self.handshake_cipher = ::std::option::Option::None;
     }
@@ -1050,20 +989,20 @@
 
     // Param is passed by value, moved
     pub fn set_handshake_cipher(&mut self, v: Ukey2HandshakeCipher) {
-        self.handshake_cipher = ::std::option::Option::Some(v);
+        self.handshake_cipher = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v));
     }
 
     // optional bytes public_key = 4;
 
-
-    pub fn get_public_key(&self) -> &[u8] {
+    pub fn public_key(&self) -> &[u8] {
         match self.public_key.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_public_key(&mut self) {
-        self.public_key.clear();
+        self.public_key = ::std::option::Option::None;
     }
 
     pub fn has_public_key(&self) -> bool {
@@ -1072,14 +1011,14 @@
 
     // Param is passed by value, moved
     pub fn set_public_key(&mut self, v: ::std::vec::Vec<u8>) {
-        self.public_key = ::protobuf::SingularField::some(v);
+        self.public_key = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_public_key(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.public_key.is_none() {
-            self.public_key.set_default();
+            self.public_key = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.public_key.as_mut().unwrap()
     }
@@ -1088,35 +1027,71 @@
     pub fn take_public_key(&mut self) -> ::std::vec::Vec<u8> {
         self.public_key.take().unwrap_or_else(|| ::std::vec::Vec::new())
     }
+
+    // optional string selected_next_protocol = 5;
+
+    pub fn selected_next_protocol(&self) -> &str {
+        match self.selected_next_protocol.as_ref() {
+            Some(v) => v,
+            None => "",
+        }
+    }
+
+    pub fn clear_selected_next_protocol(&mut self) {
+        self.selected_next_protocol = ::std::option::Option::None;
+    }
+
+    pub fn has_selected_next_protocol(&self) -> bool {
+        self.selected_next_protocol.is_some()
+    }
+
+    // Param is passed by value, moved
+    pub fn set_selected_next_protocol(&mut self, v: ::std::string::String) {
+        self.selected_next_protocol = ::std::option::Option::Some(v);
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_selected_next_protocol(&mut self) -> &mut ::std::string::String {
+        if self.selected_next_protocol.is_none() {
+            self.selected_next_protocol = ::std::option::Option::Some(::std::string::String::new());
+        }
+        self.selected_next_protocol.as_mut().unwrap()
+    }
+
+    // Take field
+    pub fn take_selected_next_protocol(&mut self) -> ::std::string::String {
+        self.selected_next_protocol.take().unwrap_or_else(|| ::std::string::String::new())
+    }
 }
 
 impl ::protobuf::Message for Ukey2ServerInit {
+    const NAME: &'static str = "Ukey2ServerInit";
+
     fn is_initialized(&self) -> bool {
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int32()?;
-                    self.version = ::std::option::Option::Some(tmp);
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                8 => {
+                    self.version = ::std::option::Option::Some(is.read_int32()?);
                 },
-                2 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.random)?;
+                18 => {
+                    self.random = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                3 => {
-                    ::protobuf::rt::read_proto2_enum_with_unknown_fields_into(wire_type, is, &mut self.handshake_cipher, 3, &mut self.unknown_fields)?
+                24 => {
+                    self.handshake_cipher = ::std::option::Option::Some(is.read_enum_or_unknown()?);
                 },
-                4 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.public_key)?;
+                34 => {
+                    self.public_key = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                42 => {
+                    self.selected_next_protocol = ::std::option::Option::Some(is.read_string()?);
+                },
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1125,101 +1100,91 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
         if let Some(v) = self.version {
-            my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint);
+            my_size += ::protobuf::rt::int32_size(1, v);
         }
-        if let Some(ref v) = self.random.as_ref() {
+        if let Some(v) = self.random.as_ref() {
             my_size += ::protobuf::rt::bytes_size(2, &v);
         }
         if let Some(v) = self.handshake_cipher {
-            my_size += ::protobuf::rt::enum_size(3, v);
+            my_size += ::protobuf::rt::int32_size(3, v.value());
         }
-        if let Some(ref v) = self.public_key.as_ref() {
+        if let Some(v) = self.public_key.as_ref() {
             my_size += ::protobuf::rt::bytes_size(4, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        if let Some(v) = self.selected_next_protocol.as_ref() {
+            my_size += ::protobuf::rt::string_size(5, &v);
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
         if let Some(v) = self.version {
             os.write_int32(1, v)?;
         }
-        if let Some(ref v) = self.random.as_ref() {
-            os.write_bytes(2, &v)?;
+        if let Some(v) = self.random.as_ref() {
+            os.write_bytes(2, v)?;
         }
         if let Some(v) = self.handshake_cipher {
-            os.write_enum(3, ::protobuf::ProtobufEnum::value(&v))?;
+            os.write_enum(3, ::protobuf::EnumOrUnknown::value(&v))?;
         }
-        if let Some(ref v) = self.public_key.as_ref() {
-            os.write_bytes(4, &v)?;
+        if let Some(v) = self.public_key.as_ref() {
+            os.write_bytes(4, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        if let Some(v) = self.selected_next_protocol.as_ref() {
+            os.write_string(5, v)?;
+        }
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> Ukey2ServerInit {
         Ukey2ServerInit::new()
     }
 
-    fn default_instance() -> &'static Ukey2ServerInit {
-        static instance: ::protobuf::rt::LazyV2<Ukey2ServerInit> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Ukey2ServerInit::new)
-    }
-}
-
-impl ::protobuf::Clear for Ukey2ServerInit {
     fn clear(&mut self) {
         self.version = ::std::option::Option::None;
-        self.random.clear();
+        self.random = ::std::option::Option::None;
         self.handshake_cipher = ::std::option::Option::None;
-        self.public_key.clear();
-        self.unknown_fields.clear();
+        self.public_key = ::std::option::Option::None;
+        self.selected_next_protocol = ::std::option::Option::None;
+        self.special_fields.clear();
     }
-}
 
-impl ::protobuf::reflect::ProtobufValue for Ukey2ServerInit {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
+    fn default_instance() -> &'static Ukey2ServerInit {
+        static instance: Ukey2ServerInit = Ukey2ServerInit {
+            version: ::std::option::Option::None,
+            random: ::std::option::Option::None,
+            handshake_cipher: ::std::option::Option::None,
+            public_key: ::std::option::Option::None,
+            selected_next_protocol: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
 #[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:securegcm.Ukey2ClientFinished)
 pub struct Ukey2ClientFinished {
     // message fields
-    public_key: ::protobuf::SingularField<::std::vec::Vec<u8>>,
+    // @@protoc_insertion_point(field:securegcm.Ukey2ClientFinished.public_key)
+    pub public_key: ::std::option::Option<::std::vec::Vec<u8>>,
     // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
+    // @@protoc_insertion_point(special_field:securegcm.Ukey2ClientFinished.special_fields)
+    pub special_fields: ::protobuf::SpecialFields,
 }
 
 impl<'a> ::std::default::Default for &'a Ukey2ClientFinished {
@@ -1235,15 +1200,15 @@
 
     // optional bytes public_key = 1;
 
-
-    pub fn get_public_key(&self) -> &[u8] {
+    pub fn public_key(&self) -> &[u8] {
         match self.public_key.as_ref() {
-            Some(v) => &v,
+            Some(v) => v,
             None => &[],
         }
     }
+
     pub fn clear_public_key(&mut self) {
-        self.public_key.clear();
+        self.public_key = ::std::option::Option::None;
     }
 
     pub fn has_public_key(&self) -> bool {
@@ -1252,14 +1217,14 @@
 
     // Param is passed by value, moved
     pub fn set_public_key(&mut self, v: ::std::vec::Vec<u8>) {
-        self.public_key = ::protobuf::SingularField::some(v);
+        self.public_key = ::std::option::Option::Some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
     pub fn mut_public_key(&mut self) -> &mut ::std::vec::Vec<u8> {
         if self.public_key.is_none() {
-            self.public_key.set_default();
+            self.public_key = ::std::option::Option::Some(::std::vec::Vec::new());
         }
         self.public_key.as_mut().unwrap()
     }
@@ -1271,19 +1236,20 @@
 }
 
 impl ::protobuf::Message for Ukey2ClientFinished {
+    const NAME: &'static str = "Ukey2ClientFinished";
+
     fn is_initialized(&self) -> bool {
         true
     }
 
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.public_key)?;
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+        while let Some(tag) = is.read_raw_tag_or_eof()? {
+            match tag {
+                10 => {
+                    self.public_key = ::std::option::Option::Some(is.read_bytes()?);
                 },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                tag => {
+                    ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
                 },
             };
         }
@@ -1292,81 +1258,64 @@
 
     // Compute sizes of nested messages
     #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
+    fn compute_size(&self) -> u64 {
         let mut my_size = 0;
-        if let Some(ref v) = self.public_key.as_ref() {
+        if let Some(v) = self.public_key.as_ref() {
             my_size += ::protobuf::rt::bytes_size(1, &v);
         }
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
+        my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+        self.special_fields.cached_size().set(my_size as u32);
         my_size
     }
 
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if let Some(ref v) = self.public_key.as_ref() {
-            os.write_bytes(1, &v)?;
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+        if let Some(v) = self.public_key.as_ref() {
+            os.write_bytes(1, v)?;
         }
-        os.write_unknown_fields(self.get_unknown_fields())?;
+        os.write_unknown_fields(self.special_fields.unknown_fields())?;
         ::std::result::Result::Ok(())
     }
 
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
+    fn special_fields(&self) -> &::protobuf::SpecialFields {
+        &self.special_fields
     }
 
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
+    fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+        &mut self.special_fields
     }
 
     fn new() -> Ukey2ClientFinished {
         Ukey2ClientFinished::new()
     }
 
-    fn default_instance() -> &'static Ukey2ClientFinished {
-        static instance: ::protobuf::rt::LazyV2<Ukey2ClientFinished> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(Ukey2ClientFinished::new)
-    }
-}
-
-impl ::protobuf::Clear for Ukey2ClientFinished {
     fn clear(&mut self) {
-        self.public_key.clear();
-        self.unknown_fields.clear();
+        self.public_key = ::std::option::Option::None;
+        self.special_fields.clear();
+    }
+
+    fn default_instance() -> &'static Ukey2ClientFinished {
+        static instance: Ukey2ClientFinished = Ukey2ClientFinished {
+            public_key: ::std::option::Option::None,
+            special_fields: ::protobuf::SpecialFields::new(),
+        };
+        &instance
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for Ukey2ClientFinished {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
-#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
+// @@protoc_insertion_point(enum:securegcm.Ukey2HandshakeCipher)
 pub enum Ukey2HandshakeCipher {
+    // @@protoc_insertion_point(enum_value:securegcm.Ukey2HandshakeCipher.RESERVED)
     RESERVED = 0,
+    // @@protoc_insertion_point(enum_value:securegcm.Ukey2HandshakeCipher.P256_SHA512)
     P256_SHA512 = 100,
+    // @@protoc_insertion_point(enum_value:securegcm.Ukey2HandshakeCipher.CURVE25519_SHA512)
     CURVE25519_SHA512 = 200,
 }
 
-impl ::protobuf::ProtobufEnum for Ukey2HandshakeCipher {
+impl ::protobuf::Enum for Ukey2HandshakeCipher {
+    const NAME: &'static str = "Ukey2HandshakeCipher";
+
     fn value(&self) -> i32 {
         *self as i32
     }
@@ -1380,17 +1329,11 @@
         }
     }
 
-    fn values() -> &'static [Self] {
-        static values: &'static [Ukey2HandshakeCipher] = &[
-            Ukey2HandshakeCipher::RESERVED,
-            Ukey2HandshakeCipher::P256_SHA512,
-            Ukey2HandshakeCipher::CURVE25519_SHA512,
-        ];
-        values
-    }
-}
-
-impl ::std::marker::Copy for Ukey2HandshakeCipher {
+    const VALUES: &'static [Ukey2HandshakeCipher] = &[
+        Ukey2HandshakeCipher::RESERVED,
+        Ukey2HandshakeCipher::P256_SHA512,
+        Ukey2HandshakeCipher::CURVE25519_SHA512,
+    ];
 }
 
 impl ::std::default::Default for Ukey2HandshakeCipher {
@@ -1399,8 +1342,3 @@
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for Ukey2HandshakeCipher {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
-    }
-}
diff --git a/nearby/crypto/crypto_provider/src/hkdf.rs b/nearby/crypto/crypto_provider/src/hkdf.rs
index dab4e13..c905302 100644
--- a/nearby/crypto/crypto_provider/src/hkdf.rs
+++ b/nearby/crypto/crypto_provider/src/hkdf.rs
@@ -33,3 +33,292 @@
 /// an invalid length
 #[derive(Debug)]
 pub struct InvalidLength;
+
+/// Test cases exported for testing specific hkdf implementations
+#[cfg(feature = "testing")]
+pub mod testing {
+    extern crate alloc;
+    use crate::hkdf::Hkdf;
+    pub use crate::testing::prelude::*;
+    use crate::CryptoProvider;
+    use alloc::vec;
+    use alloc::vec::Vec;
+    use core::iter;
+    use core::marker::PhantomData;
+    use hex_literal::hex;
+    use rstest_reuse::template;
+
+    /// Generates the test cases to validate the hkdf implementation.
+    /// For example, to test `MyCryptoProvider`:
+    ///
+    /// ```
+    /// mod tests {
+    ///     use std::marker::PhantomData;
+    ///     use crypto_provider::testing::CryptoProviderTestCase;
+    ///     #[apply(hkdf_test_cases)]
+    ///     fn hkdf_tests(testcase: CryptoProviderTestCase<MyCryptoProvider>){
+    ///         testcase(PhantomData::<MyCryptoProvider>);
+    ///     }
+    /// }
+    /// ```
+    #[template]
+    #[export]
+    #[rstest]
+    #[case::basic_test_hkdf(basic_test_hkdf)]
+    #[case::test_rfc5869_sha256(test_rfc5869_sha256)]
+    #[case::test_lengths(test_lengths)]
+    #[case::test_max_length(test_max_length)]
+    #[case::test_max_length_exceeded(test_max_length_exceeded)]
+    #[case::test_unsupported_length(test_unsupported_length)]
+    #[case::test_expand_multi_info(test_expand_multi_info)]
+    #[case::run_hkdf_sha256_vectors(run_hkdf_sha256_vectors)]
+    #[case::run_hkdf_sha512_vectors(run_hkdf_sha512_vectors)]
+    fn hkdf_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>) {}
+
+    const MAX_SHA256_LENGTH: usize = 255 * (256 / 8); // =8160
+
+    ///
+    pub struct Test<'a> {
+        ikm: &'a [u8],
+        salt: &'a [u8],
+        info: &'a [u8],
+        okm: &'a [u8],
+    }
+
+    /// data taken from sample code in Readme of crates.io page
+    pub fn basic_test_hkdf<C: CryptoProvider>(_: PhantomData<C>) {
+        let ikm = hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
+        let salt = hex!("000102030405060708090a0b0c");
+        let info = hex!("f0f1f2f3f4f5f6f7f8f9");
+
+        let hk = C::HkdfSha256::new(Some(&salt[..]), &ikm);
+        let mut okm = [0u8; 42];
+        hk.expand(&info, &mut okm)
+            .expect("42 is a valid length for Sha256 to output");
+
+        let expected = hex!(
+            "
+        3cb25f25faacd57a90434f64d0362f2a
+        2d2d0a90cf1a5a4c5db02d56ecc4c5bf
+        34007208d5b887185865
+        "
+        );
+        assert_eq!(okm, expected);
+    }
+
+    // Test Vectors from https://tools.ietf.org/html/rfc5869.
+    #[rustfmt::skip]
+    ///
+    pub fn test_rfc5869_sha256<C: CryptoProvider>(_: PhantomData<C>) {
+        let tests = [
+            Test {
+                // Test Case 1
+                ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+                salt: &hex!("000102030405060708090a0b0c"),
+                info: &hex!("f0f1f2f3f4f5f6f7f8f9"),
+                okm: &hex!("
+                    3cb25f25faacd57a90434f64d0362f2a
+                    2d2d0a90cf1a5a4c5db02d56ecc4c5bf
+                    34007208d5b887185865
+                "),
+            },
+            Test {
+                // Test Case 2
+                ikm: &hex!("
+                    000102030405060708090a0b0c0d0e0f
+                    101112131415161718191a1b1c1d1e1f
+                    202122232425262728292a2b2c2d2e2f
+                    303132333435363738393a3b3c3d3e3f
+                    404142434445464748494a4b4c4d4e4f
+                "),
+                salt: &hex!("
+                    606162636465666768696a6b6c6d6e6f
+                    707172737475767778797a7b7c7d7e7f
+                    808182838485868788898a8b8c8d8e8f
+                    909192939495969798999a9b9c9d9e9f
+                    a0a1a2a3a4a5a6a7a8a9aaabacadaeaf
+                "),
+                info: &hex!("
+                    b0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+                    c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+                    d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+                    e0e1e2e3e4e5e6e7e8e9eaebecedeeef
+                    f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+                "),
+                okm: &hex!("
+                    b11e398dc80327a1c8e7f78c596a4934
+                    4f012eda2d4efad8a050cc4c19afa97c
+                    59045a99cac7827271cb41c65e590e09
+                    da3275600c2f09b8367793a9aca3db71
+                    cc30c58179ec3e87c14c01d5c1f3434f
+                    1d87
+                "),
+            },
+            Test {
+                // Test Case 3
+                ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+                salt: &hex!(""),
+                info: &hex!(""),
+                okm: &hex!("
+                    8da4e775a563c18f715f802a063c5a31
+                    b8a11f5c5ee1879ec3454e5f3c738d2d
+                    9d201395faa4b61a96c8
+                "),
+            },
+        ];
+        for Test { ikm, salt, info, okm } in tests.iter() {
+            let salt = if salt.is_empty() {
+                None
+            } else {
+                Some(&salt[..])
+            };
+            let hkdf = C::HkdfSha256::new(salt, ikm);
+            let mut okm2 = vec![0u8; okm.len()];
+            assert!(hkdf.expand(&info[..], &mut okm2).is_ok());
+            assert_eq!(okm2[..], okm[..]);
+        }
+    }
+
+    ///
+    pub fn test_lengths<C: CryptoProvider>(_: PhantomData<C>) {
+        let hkdf = C::HkdfSha256::new(None, &[]);
+        let mut longest = vec![0u8; MAX_SHA256_LENGTH];
+        assert!(hkdf.expand(&[], &mut longest).is_ok());
+        // Runtime is O(length), so exhaustively testing all legal lengths
+        // would take too long (at least without --release). Only test a
+        // subset: the first 500, the last 10, and every 100th in between.
+        // 0 is an invalid key length for openssl, so start at 1
+        let lengths = (1..MAX_SHA256_LENGTH + 1)
+            .filter(|&len| !(500..=MAX_SHA256_LENGTH - 10).contains(&len) || len % 100 == 0);
+
+        for length in lengths {
+            let mut okm = vec![0u8; length];
+
+            assert!(hkdf.expand(&[], &mut okm).is_ok());
+            assert_eq!(okm.len(), length);
+            assert_eq!(okm[..], longest[..length]);
+        }
+    }
+
+    ///
+    pub fn test_max_length<C: CryptoProvider>(_: PhantomData<C>) {
+        let hkdf = C::HkdfSha256::new(Some(&[]), &[]);
+        let mut okm = vec![0u8; MAX_SHA256_LENGTH];
+        assert!(hkdf.expand(&[], &mut okm).is_ok());
+    }
+
+    ///
+    pub fn test_max_length_exceeded<C: CryptoProvider>(_: PhantomData<C>) {
+        let hkdf = C::HkdfSha256::new(Some(&[]), &[]);
+        let mut okm = vec![0u8; MAX_SHA256_LENGTH + 1];
+        assert!(hkdf.expand(&[], &mut okm).is_err());
+    }
+
+    ///
+    pub fn test_unsupported_length<C: CryptoProvider>(_: PhantomData<C>) {
+        let hkdf = C::HkdfSha256::new(Some(&[]), &[]);
+        let mut okm = vec![0u8; 90000];
+        assert!(hkdf.expand(&[], &mut okm).is_err());
+    }
+
+    ///
+    pub fn test_expand_multi_info<C: CryptoProvider>(_: PhantomData<C>) {
+        let info_components = &[
+            &b"09090909090909090909090909090909090909090909"[..],
+            &b"8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a"[..],
+            &b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0"[..],
+            &b"4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4"[..],
+            &b"1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d"[..],
+        ];
+
+        let hkdf = C::HkdfSha256::new(None, b"some ikm here");
+
+        // Compute HKDF-Expand on the concatenation of all the info components
+        let mut oneshot_res = [0u8; 16];
+        hkdf.expand(&info_components.concat(), &mut oneshot_res)
+            .unwrap();
+
+        // Now iteratively join the components of info_components until it's all 1 component. The value
+        // of HKDF-Expand should be the same throughout
+        let mut num_concatted = 0;
+        let mut info_head = Vec::new();
+
+        while num_concatted < info_components.len() {
+            info_head.extend(info_components[num_concatted]);
+
+            // Build the new input to be the info head followed by the remaining components
+            let input: Vec<&[u8]> = iter::once(info_head.as_slice())
+                .chain(info_components.iter().cloned().skip(num_concatted + 1))
+                .collect();
+
+            // Compute and compare to the one-shot answer
+            let mut multipart_res = [0u8; 16];
+            hkdf.expand_multi_info(&input, &mut multipart_res).unwrap();
+            assert_eq!(multipart_res, oneshot_res);
+            num_concatted += 1;
+        }
+    }
+
+    ///
+    pub fn run_hkdf_sha256_vectors<C: CryptoProvider>(_: PhantomData<C>) {
+        run_hkdf_test_vectors::<C::HkdfSha256>(HashAlg::Sha256)
+    }
+
+    ///
+    pub fn run_hkdf_sha512_vectors<C: CryptoProvider>(_: PhantomData<C>) {
+        run_hkdf_test_vectors::<C::HkdfSha512>(HashAlg::Sha512)
+    }
+
+    enum HashAlg {
+        Sha256,
+        Sha512,
+    }
+
+    ///
+    fn run_hkdf_test_vectors<K: Hkdf>(hash: HashAlg) {
+        let test_name = match hash {
+            HashAlg::Sha256 => wycheproof::hkdf::TestName::HkdfSha256,
+            HashAlg::Sha512 => wycheproof::hkdf::TestName::HkdfSha512,
+        };
+
+        let test_set =
+            wycheproof::hkdf::TestSet::load(test_name).expect("should be able to load test set");
+        for test_group in test_set.test_groups {
+            for test in test_group.tests {
+                let ikm = test.ikm;
+                let salt = test.salt;
+                let info = test.info;
+                let okm = test.okm;
+                let tc_id = test.tc_id;
+                if let Some(desc) = run_test::<K>(
+                    ikm.as_slice(),
+                    salt.as_slice(),
+                    info.as_slice(),
+                    okm.as_slice(),
+                ) {
+                    panic!(
+                        "\n\
+                         Failed test {tc_id}: {desc}\n\
+                         ikm:\t{ikm:?}\n\
+                         salt:\t{salt:?}\n\
+                         info:\t{info:?}\n\
+                         okm:\t{okm:?}\n"
+                    );
+                }
+            }
+        }
+    }
+
+    fn run_test<K: Hkdf>(ikm: &[u8], salt: &[u8], info: &[u8], okm: &[u8]) -> Option<&'static str> {
+        let prk = K::new(Some(salt), ikm);
+        let mut got_okm = vec![0; okm.len()];
+
+        if prk.expand(info, &mut got_okm).is_err() {
+            return Some("prk expand");
+        }
+        if got_okm != okm {
+            return Some("mismatch in okm");
+        }
+        None
+    }
+}
diff --git a/nearby/crypto/crypto_provider/src/hmac.rs b/nearby/crypto/crypto_provider/src/hmac.rs
index c5a9ae1..40be189 100644
--- a/nearby/crypto/crypto_provider/src/hmac.rs
+++ b/nearby/crypto/crypto_provider/src/hmac.rs
@@ -44,3 +44,125 @@
 /// Error output when the provided key material length is invalid
 #[derive(Debug)]
 pub struct InvalidLength;
+
+/// Test cases exported for testing specific hmac implementations
+#[cfg(feature = "testing")]
+pub mod testing {
+    use crate::hmac::Hmac;
+    use crate::rstest_reuse::template;
+    pub use crate::testing::prelude::*;
+    use crate::CryptoProvider;
+    use core::cmp::min;
+    use core::marker::PhantomData;
+    use wycheproof::TestResult;
+
+    /// Generates the test cases to validate the hmac implementation.
+    /// For example, to test `MyCryptoProvider`:
+    ///
+    /// ```
+    /// mod tests {
+    ///     use std::marker::PhantomData;
+    ///     use crypto_provider::testing::CryptoProviderTestCase;
+    ///     #[apply(hmac_test_cases)]
+    ///     fn hmac_tests(testcase: CryptoProviderTestCase<MyCryptoProvider>){
+    ///         testcase(PhantomData::<MyCryptoProvider>);
+    ///     }
+    /// }
+    /// ```
+    #[template]
+    #[export]
+    #[rstest]
+    #[case::hmac_sha256_test_vectors(hmac_sha256_test_vectors)]
+    #[case::hmac_sha512_test_vectors(hmac_sha512_test_vectors)]
+    fn hmac_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>) {}
+
+    /// Run wycheproof hmac sha256 test vectors on provided CryptoProvider
+    pub fn hmac_sha256_test_vectors<C: CryptoProvider>(_: PhantomData<C>) {
+        run_hmac_test_vectors::<32, C::HmacSha256>(HashAlg::Sha256)
+    }
+
+    /// Run wycheproof hmac sha512 test vectors on provided CryptoProvider
+    pub fn hmac_sha512_test_vectors<C: CryptoProvider>(_: PhantomData<C>) {
+        run_hmac_test_vectors::<64, C::HmacSha512>(HashAlg::Sha512)
+    }
+
+    enum HashAlg {
+        Sha256,
+        Sha512,
+    }
+
+    // Tests vectors from Project Wycheproof:
+    // https://github.com/google/wycheproof
+    fn run_hmac_test_vectors<const N: usize, H: Hmac<N>>(hash: HashAlg) {
+        let test_name = match hash {
+            HashAlg::Sha256 => wycheproof::mac::TestName::HmacSha256,
+            HashAlg::Sha512 => wycheproof::mac::TestName::HmacSha512,
+        };
+        let test_set =
+            wycheproof::mac::TestSet::load(test_name).expect("should be able to load test set");
+
+        for test_group in test_set.test_groups {
+            for test in test_group.tests {
+                let key = test.key;
+                let msg = test.msg;
+                let tag = test.tag;
+                let tc_id = test.tc_id;
+                let valid = match test.result {
+                    TestResult::Valid | TestResult::Acceptable => true,
+                    TestResult::Invalid => false,
+                };
+
+                if let Some(desc) =
+                    run_test::<N, H>(key.as_slice(), msg.as_slice(), tag.as_slice(), valid)
+                {
+                    panic!(
+                        "\n\
+                         Failed test {tc_id}: {desc}\n\
+                         key:\t{key:?}\n\
+                         msg:\t{msg:?}\n\
+                         tag:\t{tag:?}\n",
+                    );
+                }
+            }
+        }
+    }
+
+    fn run_test<const N: usize, H: Hmac<N>>(
+        key: &[u8],
+        input: &[u8],
+        tag: &[u8],
+        valid_data: bool,
+    ) -> Option<&'static str> {
+        let mut mac = H::new_from_slice(key).unwrap();
+        mac.update(input);
+        let result = mac.finalize();
+        let n = tag.len();
+        let result_bytes = &result[..n];
+
+        if valid_data {
+            if result_bytes != tag {
+                return Some("whole message");
+            }
+        } else {
+            return if result_bytes == tag {
+                Some("invalid should not match")
+            } else {
+                None
+            };
+        }
+
+        // test reading different chunk sizes
+        for chunk_size in 1..min(64, input.len()) {
+            let mut mac = H::new_from_slice(key).unwrap();
+            for chunk in input.chunks(chunk_size) {
+                mac.update(chunk);
+            }
+            let res = mac.verify_truncated_left(tag);
+            if res.is_err() {
+                return Some("chunked message");
+            }
+        }
+
+        None
+    }
+}
diff --git a/nearby/crypto/crypto_provider/src/lib.rs b/nearby/crypto/crypto_provider/src/lib.rs
index e9ce8b8..a61370c 100644
--- a/nearby/crypto/crypto_provider/src/lib.rs
+++ b/nearby/crypto/crypto_provider/src/lib.rs
@@ -46,11 +46,11 @@
 /// Uber crypto trait which defines the traits for all crypto primitives as associated types
 pub trait CryptoProvider: Clone + Debug + PartialEq + Eq + Send {
     /// The Hkdf type which implements the hkdf trait
-    type HkdfSha256: hkdf::Hkdf + Clone;
+    type HkdfSha256: hkdf::Hkdf;
     /// The Hmac type which implements the hmac trait
     type HmacSha256: hmac::Hmac<32>;
     /// The Hkdf type which implements the hkdf trait
-    type HkdfSha512: hkdf::Hkdf + Clone;
+    type HkdfSha512: hkdf::Hkdf;
     /// The Hmac type which implements the hmac trait
     type HmacSha512: hmac::Hmac<64>;
     /// The AES-CBC-PKCS7 implementation to use
diff --git a/nearby/crypto/crypto_provider/tests/hkdf_tests.rs b/nearby/crypto/crypto_provider/tests/hkdf_tests.rs
deleted file mode 100644
index 72d8dcc..0000000
--- a/nearby/crypto/crypto_provider/tests/hkdf_tests.rs
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright 2022 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.
-
-/// Tests for both openssl and rust-crypto crypto_provider impls
-use crypto_provider::hkdf::Hkdf as _;
-use crypto_provider::CryptoProvider;
-use crypto_provider_openssl::Openssl;
-use crypto_provider_rustcrypto::RustCrypto;
-use hex_literal::hex;
-use std::iter;
-
-struct Test<'a> {
-    ikm: &'a [u8],
-    salt: &'a [u8],
-    info: &'a [u8],
-    okm: &'a [u8],
-}
-
-#[test]
-fn basic_test_rc() {
-    basic_test_hkdf::<RustCrypto>();
-}
-
-#[test]
-fn basic_test_openssl() {
-    basic_test_hkdf::<Openssl>();
-}
-
-/// data taken from sample code in Readme of crates.io page
-fn basic_test_hkdf<C: CryptoProvider>() {
-    let ikm = hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
-    let salt = hex!("000102030405060708090a0b0c");
-    let info = hex!("f0f1f2f3f4f5f6f7f8f9");
-
-    let hk = C::HkdfSha256::new(Some(&salt[..]), &ikm);
-    let mut okm = [0u8; 42];
-    hk.expand(&info, &mut okm)
-        .expect("42 is a valid length for Sha256 to output");
-
-    let expected = hex!(
-        "
-        3cb25f25faacd57a90434f64d0362f2a
-        2d2d0a90cf1a5a4c5db02d56ecc4c5bf
-        34007208d5b887185865
-        "
-    );
-    assert_eq!(okm, expected);
-}
-
-#[test]
-fn rfc5869_sha256_rc() {
-    test_rfc5869_sha256::<RustCrypto>();
-}
-
-#[test]
-fn rfc5869_sha256_openssl() {
-    test_rfc5869_sha256::<Openssl>();
-}
-
-// Test Vectors from https://tools.ietf.org/html/rfc5869.
-#[rustfmt::skip]
-fn test_rfc5869_sha256<C: CryptoProvider>() {
-    let tests = [
-        Test {
-            // Test Case 1
-            ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
-            salt: &hex!("000102030405060708090a0b0c"),
-            info: &hex!("f0f1f2f3f4f5f6f7f8f9"),
-            okm: &hex!("
-                3cb25f25faacd57a90434f64d0362f2a
-                2d2d0a90cf1a5a4c5db02d56ecc4c5bf
-                34007208d5b887185865
-            "),
-        },
-        Test {
-            // Test Case 2
-            ikm: &hex!("
-                000102030405060708090a0b0c0d0e0f
-                101112131415161718191a1b1c1d1e1f
-                202122232425262728292a2b2c2d2e2f
-                303132333435363738393a3b3c3d3e3f
-                404142434445464748494a4b4c4d4e4f
-            "),
-            salt: &hex!("
-                606162636465666768696a6b6c6d6e6f
-                707172737475767778797a7b7c7d7e7f
-                808182838485868788898a8b8c8d8e8f
-                909192939495969798999a9b9c9d9e9f
-                a0a1a2a3a4a5a6a7a8a9aaabacadaeaf
-            "),
-            info: &hex!("
-                b0b1b2b3b4b5b6b7b8b9babbbcbdbebf
-                c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
-                d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
-                e0e1e2e3e4e5e6e7e8e9eaebecedeeef
-                f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
-            "),
-            okm: &hex!("
-                b11e398dc80327a1c8e7f78c596a4934
-                4f012eda2d4efad8a050cc4c19afa97c
-                59045a99cac7827271cb41c65e590e09
-                da3275600c2f09b8367793a9aca3db71
-                cc30c58179ec3e87c14c01d5c1f3434f
-                1d87
-            "),
-        },
-        Test {
-            // Test Case 3
-            ikm: &hex!("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
-            salt: &hex!(""),
-            info: &hex!(""),
-            okm: &hex!("
-                8da4e775a563c18f715f802a063c5a31
-                b8a11f5c5ee1879ec3454e5f3c738d2d
-                9d201395faa4b61a96c8
-            "),
-        },
-    ];
-    for Test { ikm, salt, info, okm } in tests.iter() {
-        let salt = if salt.is_empty() {
-            None
-        } else {
-            Some(&salt[..])
-        };
-        let hkdf = C::HkdfSha256::new(salt, ikm);
-        let mut okm2 = vec![0u8; okm.len()];
-        assert!(hkdf.expand(&info[..], &mut okm2).is_ok());
-        assert_eq!(okm2[..], okm[..]);
-    }
-}
-
-const MAX_SHA256_LENGTH: usize = 255 * (256 / 8); // =8160
-
-#[test]
-fn lengths_rc() {
-    test_lengths::<RustCrypto>()
-}
-
-#[test]
-fn lengths_openssl() {
-    test_lengths::<Openssl>()
-}
-
-fn test_lengths<C: CryptoProvider>() {
-    let hkdf = C::HkdfSha256::new(None, &[]);
-    let mut longest = vec![0u8; MAX_SHA256_LENGTH];
-    assert!(hkdf.expand(&[], &mut longest).is_ok());
-    // Runtime is O(length), so exhaustively testing all legal lengths
-    // would take too long (at least without --release). Only test a
-    // subset: the first 500, the last 10, and every 100th in between.
-    // 0 is an invalid key length for openssl, so start at 1
-    let lengths = (1..MAX_SHA256_LENGTH + 1)
-        .filter(|&len| !(500..=MAX_SHA256_LENGTH - 10).contains(&len) || len % 100 == 0);
-
-    for length in lengths {
-        let mut okm = vec![0u8; length];
-
-        assert!(hkdf.expand(&[], &mut okm).is_ok());
-        assert_eq!(okm.len(), length);
-        assert_eq!(okm[..], longest[..length]);
-    }
-}
-
-#[test]
-fn max_length_rc() {
-    test_max_length::<RustCrypto>();
-}
-
-#[test]
-fn max_length_openssl() {
-    test_max_length::<Openssl>();
-}
-
-fn test_max_length<C: CryptoProvider>() {
-    let hkdf = C::HkdfSha256::new(Some(&[]), &[]);
-    let mut okm = vec![0u8; MAX_SHA256_LENGTH];
-    assert!(hkdf.expand(&[], &mut okm).is_ok());
-}
-
-#[test]
-fn max_length_exceeded_rc() {
-    test_max_length_exceeded::<RustCrypto>();
-}
-
-#[test]
-fn max_length_exceeded_openssl() {
-    test_max_length_exceeded::<Openssl>();
-}
-
-fn test_max_length_exceeded<C: CryptoProvider>() {
-    let hkdf = C::HkdfSha256::new(Some(&[]), &[]);
-    let mut okm = vec![0u8; MAX_SHA256_LENGTH + 1];
-    assert!(hkdf.expand(&[], &mut okm).is_err());
-}
-
-#[test]
-fn unsupported_length_rc() {
-    test_unsupported_length::<RustCrypto>();
-}
-
-#[test]
-fn unsupported_length_openssl() {
-    test_unsupported_length::<Openssl>();
-}
-
-fn test_unsupported_length<C: CryptoProvider>() {
-    let hkdf = C::HkdfSha256::new(Some(&[]), &[]);
-    let mut okm = vec![0u8; 90000];
-    assert!(hkdf.expand(&[], &mut okm).is_err());
-}
-
-#[test]
-fn expand_multi_info_rc() {
-    test_expand_multi_info::<RustCrypto>();
-}
-
-#[test]
-fn expand_multi_info_openssl() {
-    test_expand_multi_info::<Openssl>();
-}
-
-fn test_expand_multi_info<C: CryptoProvider>() {
-    let info_components = &[
-        &b"09090909090909090909090909090909090909090909"[..],
-        &b"8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a8a"[..],
-        &b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0"[..],
-        &b"4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4c4"[..],
-        &b"1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d"[..],
-    ];
-
-    let hkdf = C::HkdfSha256::new(None, b"some ikm here");
-
-    // Compute HKDF-Expand on the concatenation of all the info components
-    let mut oneshot_res = [0u8; 16];
-    hkdf.expand(&info_components.concat(), &mut oneshot_res)
-        .unwrap();
-
-    // Now iteratively join the components of info_components until it's all 1 component. The value
-    // of HKDF-Expand should be the same throughout
-    let mut num_concatted = 0;
-    let mut info_head = Vec::new();
-
-    while num_concatted < info_components.len() {
-        info_head.extend(info_components[num_concatted]);
-
-        // Build the new input to be the info head followed by the remaining components
-        let input: Vec<&[u8]> = iter::once(info_head.as_slice())
-            .chain(info_components.iter().cloned().skip(num_concatted + 1))
-            .collect();
-
-        // Compute and compare to the one-shot answer
-        let mut multipart_res = [0u8; 16];
-        hkdf.expand_multi_info(&input, &mut multipart_res).unwrap();
-        assert_eq!(multipart_res, oneshot_res);
-        num_concatted += 1;
-    }
-}
-
-#[test]
-fn hkdf_sha_256_wycheproof_test_vectors_rc() {
-    run_hkdf_test_vectors::<<RustCrypto as CryptoProvider>::HkdfSha256>(HashAlg::Sha256)
-}
-
-#[test]
-fn hkdf_sha_512_wycheproof_test_vectors_rc() {
-    run_hkdf_test_vectors::<<RustCrypto as CryptoProvider>::HkdfSha512>(HashAlg::Sha512)
-}
-
-#[test]
-fn hkdf_sha_256_wycheproof_test_vectors_openssl() {
-    run_hkdf_test_vectors::<<Openssl as CryptoProvider>::HkdfSha256>(HashAlg::Sha256)
-}
-
-#[test]
-fn hkdf_sha_512_wycheproof_test_vectors_openssl() {
-    run_hkdf_test_vectors::<<Openssl as CryptoProvider>::HkdfSha512>(HashAlg::Sha512)
-}
-
-enum HashAlg {
-    Sha256,
-    Sha512,
-}
-
-fn run_hkdf_test_vectors<K: crypto_provider::hkdf::Hkdf>(hash: HashAlg) {
-    let test_name = match hash {
-        HashAlg::Sha256 => wycheproof::hkdf::TestName::HkdfSha256,
-        HashAlg::Sha512 => wycheproof::hkdf::TestName::HkdfSha512,
-    };
-
-    let test_set =
-        wycheproof::hkdf::TestSet::load(test_name).expect("should be able to load test set");
-    for test_group in test_set.test_groups {
-        for test in test_group.tests {
-            let ikm = test.ikm;
-            let salt = test.salt;
-            let info = test.info;
-            let okm = test.okm;
-            let tc_id = test.tc_id;
-            if let Some(desc) = run_test::<K>(
-                ikm.as_slice(),
-                salt.as_slice(),
-                info.as_slice(),
-                okm.as_slice(),
-            ) {
-                panic!(
-                    "\n\
-                         Failed test {tc_id}: {desc}\n\
-                         ikm:\t{ikm:?}\n\
-                         salt:\t{salt:?}\n\
-                         info:\t{info:?}\n\
-                         okm:\t{okm:?}\n"
-                );
-            }
-        }
-    }
-}
-
-fn run_test<K: crypto_provider::hkdf::Hkdf>(
-    ikm: &[u8],
-    salt: &[u8],
-    info: &[u8],
-    okm: &[u8],
-) -> Option<&'static str> {
-    let prk = K::new(Some(salt), ikm);
-    let mut got_okm = vec![0; okm.len()];
-
-    if prk.expand(info, &mut got_okm).is_err() {
-        return Some("prk expand");
-    }
-    if got_okm != okm {
-        return Some("mismatch in okm");
-    }
-    None
-}
diff --git a/nearby/crypto/crypto_provider/tests/hmac_tests.rs b/nearby/crypto/crypto_provider/tests/hmac_tests.rs
deleted file mode 100644
index b7b64ee..0000000
--- a/nearby/crypto/crypto_provider/tests/hmac_tests.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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 core::cmp::min;
-use crypto_provider::CryptoProvider;
-use crypto_provider_openssl::Openssl;
-use crypto_provider_rustcrypto::RustCrypto;
-use wycheproof::TestResult;
-
-#[test]
-fn hmac_sha_256_wycheproof_test_vectors_rustcrypto() {
-    run_hmac_test_vectors::<32, <RustCrypto as CryptoProvider>::HmacSha256>(HashAlg::Sha256)
-}
-
-#[test]
-fn hmac_sha_256_wycheproof_test_vectors_openssl() {
-    run_hmac_test_vectors::<32, <Openssl as CryptoProvider>::HmacSha256>(HashAlg::Sha256)
-}
-
-#[test]
-fn hmac_sha_512_wycheproof_test_vectors_rustcrypto() {
-    run_hmac_test_vectors::<64, <RustCrypto as CryptoProvider>::HmacSha512>(HashAlg::Sha512)
-}
-
-#[test]
-fn hmac_sha_512_wycheproof_test_vectors_openssl() {
-    run_hmac_test_vectors::<64, <Openssl as CryptoProvider>::HmacSha512>(HashAlg::Sha512)
-}
-
-enum HashAlg {
-    Sha256,
-    Sha512,
-}
-
-// Tests vectors from Project Wycheproof:
-// https://github.com/google/wycheproof
-fn run_hmac_test_vectors<const N: usize, H: crypto_provider::hmac::Hmac<N>>(hash: HashAlg) {
-    let test_name = match hash {
-        HashAlg::Sha256 => wycheproof::mac::TestName::HmacSha256,
-        HashAlg::Sha512 => wycheproof::mac::TestName::HmacSha512,
-    };
-    let test_set =
-        wycheproof::mac::TestSet::load(test_name).expect("should be able to load test set");
-
-    for test_group in test_set.test_groups {
-        for test in test_group.tests {
-            let key = test.key;
-            let msg = test.msg;
-            let tag = test.tag;
-            let tc_id = test.tc_id;
-            let valid = match test.result {
-                TestResult::Valid | TestResult::Acceptable => true,
-                TestResult::Invalid => false,
-            };
-
-            if let Some(desc) =
-                run_test::<N, H>(key.as_slice(), msg.as_slice(), tag.as_slice(), valid)
-            {
-                panic!(
-                    "\n\
-                         Failed test {tc_id}: {desc}\n\
-                         key:\t{key:?}\n\
-                         msg:\t{msg:?}\n\
-                         tag:\t{tag:?}\n",
-                );
-            }
-        }
-    }
-}
-
-fn run_test<const N: usize, H: crypto_provider::hmac::Hmac<N>>(
-    key: &[u8],
-    input: &[u8],
-    tag: &[u8],
-    valid_data: bool,
-) -> Option<&'static str> {
-    let mut mac = H::new_from_slice(key).unwrap();
-    mac.update(input);
-    let result = mac.finalize();
-    let n = tag.len();
-    let result_bytes = &result[..n];
-
-    if valid_data {
-        if result_bytes != tag {
-            return Some("whole message");
-        }
-    } else {
-        return if result_bytes == tag {
-            Some("invalid should not match")
-        } else {
-            None
-        };
-    }
-
-    // test reading different chunk sizes
-    for chunk_size in 1..min(64, input.len()) {
-        let mut mac = H::new_from_slice(key).unwrap();
-        for chunk in input.chunks(chunk_size) {
-            mac.update(chunk);
-        }
-        let res = mac.verify_truncated_left(tag);
-        if res.is_err() {
-            return Some("chunked message");
-        }
-    }
-
-    None
-}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/aes.rs b/nearby/crypto/crypto_provider_boringssl/src/aes.rs
index a92f67e..a4f275e 100644
--- a/nearby/crypto/crypto_provider_boringssl/src/aes.rs
+++ b/nearby/crypto/crypto_provider_boringssl/src/aes.rs
@@ -12,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! Implementation of `crypto_provider::aes` types using BoringSSL.
-
 use bssl_crypto::aes::{AesDecryptKey, AesEncryptKey};
 use crypto_provider::aes::{
     Aes, Aes128Key, Aes256Key, AesBlock, AesCipher, AesDecryptCipher, AesEncryptCipher, AesKey,
diff --git a/nearby/crypto/crypto_provider_boringssl/src/hkdf.rs b/nearby/crypto/crypto_provider_boringssl/src/hkdf.rs
new file mode 100644
index 0000000..4ab0ad4
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/hkdf.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.
+
+//! BoringSSL based HKDF implementation. Unfortunately, because the OpenSSL and BoringSSL APIs
+//! diverged for HKDF, we have to have separate implementations.
+//!
+//! See the _Using BoringSSL_ section in `nearby/scripts/prepare_boringssl.sh` for instructions on
+//! how to test against BoringSSL.
+
+use bssl_crypto::digest::Md;
+use crypto_provider::hkdf::InvalidLength;
+
+/// Struct providing BoringSSL implemented Hkdf operations.
+pub struct Hkdf<M: Md>(bssl_crypto::hkdf::Hkdf<M>);
+
+impl<M: Md> crypto_provider::hkdf::Hkdf for Hkdf<M> {
+    fn new(salt: Option<&[u8]>, ikm: &[u8]) -> Self {
+        Self(bssl_crypto::hkdf::Hkdf::<M>::new(salt, ikm))
+    }
+
+    fn expand_multi_info(
+        &self,
+        info_components: &[&[u8]],
+        okm: &mut [u8],
+    ) -> Result<(), InvalidLength> {
+        if okm.is_empty() {
+            return Ok(());
+        }
+        self.0
+            .expand_multi_info(info_components, okm)
+            .map_err(|_| InvalidLength)
+    }
+
+    fn expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength> {
+        if okm.is_empty() {
+            return Ok(());
+        }
+        self.0.expand(info, okm).map_err(|_| InvalidLength)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::Boringssl;
+    use core::marker::PhantomData;
+    use crypto_provider::hkdf::testing::*;
+
+    #[apply(hkdf_test_cases)]
+    fn hkdf_tests(testcase: CryptoProviderTestCase<Boringssl>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/hmac.rs b/nearby/crypto/crypto_provider_boringssl/src/hmac.rs
new file mode 100644
index 0000000..3459c3b
--- /dev/null
+++ b/nearby/crypto/crypto_provider_boringssl/src/hmac.rs
@@ -0,0 +1,93 @@
+// 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 crypto_provider::hmac::{InvalidLength, MacError};
+
+/// BoringSSL implemented Hmac Sha256 struct
+pub struct HmacSha256(bssl_crypto::hmac::HmacSha256);
+
+impl crypto_provider::hmac::Hmac<32> for HmacSha256 {
+    fn new_from_key(key: [u8; 32]) -> Self {
+        Self(bssl_crypto::hmac::HmacSha256::new(key))
+    }
+
+    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
+        Ok(Self(bssl_crypto::hmac::HmacSha256::new_from_slice(key)))
+    }
+
+    fn update(&mut self, data: &[u8]) {
+        self.0.update(data)
+    }
+
+    fn finalize(self) -> [u8; 32] {
+        self.0.finalize()
+    }
+
+    fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> {
+        self.0.verify_slice(tag).map_err(|_| MacError)
+    }
+
+    fn verify(self, tag: [u8; 32]) -> Result<(), MacError> {
+        self.0.verify(tag).map_err(|_| MacError)
+    }
+
+    fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> {
+        self.0.verify_truncated_left(tag).map_err(|_| MacError)
+    }
+}
+
+/// BoringSSL implemented Hmac Sha512 struct
+pub struct HmacSha512(bssl_crypto::hmac::HmacSha512);
+
+impl crypto_provider::hmac::Hmac<64> for HmacSha512 {
+    fn new_from_key(key: [u8; 64]) -> Self {
+        Self(bssl_crypto::hmac::HmacSha512::new(key))
+    }
+
+    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
+        Ok(Self(bssl_crypto::hmac::HmacSha512::new_from_slice(key)))
+    }
+
+    fn update(&mut self, data: &[u8]) {
+        self.0.update(data)
+    }
+
+    fn finalize(self) -> [u8; 64] {
+        self.0.finalize()
+    }
+
+    fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> {
+        self.0.verify_slice(tag).map_err(|_| MacError)
+    }
+
+    fn verify(self, tag: [u8; 64]) -> Result<(), MacError> {
+        self.0.verify(tag).map_err(|_| MacError)
+    }
+
+    fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> {
+        self.0.verify_truncated_left(tag).map_err(|_| MacError)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::Boringssl;
+    use core::marker::PhantomData;
+    use crypto_provider::hmac::testing::*;
+
+    #[apply(hmac_test_cases)]
+    fn hmac_tests(testcase: CryptoProviderTestCase<Boringssl>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_boringssl/src/lib.rs b/nearby/crypto/crypto_provider_boringssl/src/lib.rs
index 0775172..a7e78d0 100644
--- a/nearby/crypto/crypto_provider_boringssl/src/lib.rs
+++ b/nearby/crypto/crypto_provider_boringssl/src/lib.rs
@@ -23,20 +23,28 @@
 
 //! Crate which provides impls for CryptoProvider backed by BoringSSL.
 
-use crypto_provider::CryptoProvider;
+use bssl_crypto::digest::{Sha256, Sha512};
+use crypto_provider::{CryptoProvider, CryptoRng};
 use crypto_provider_stubs::*;
 
+/// Implementation of `crypto_provider::aes` types using BoringSSL.
 pub mod aes;
 
+/// Implementations of crypto_provider::hkdf traits backed by BoringSSL
+pub mod hkdf;
+
+/// Implementations of crypto_provider::hmac traits backed by BoringSSL
+pub mod hmac;
+
 /// The BoringSSL backed struct which implements CryptoProvider
 #[derive(Default, Clone, Debug, PartialEq, Eq)]
 pub struct Boringssl;
 
 impl CryptoProvider for Boringssl {
-    type HkdfSha256 = HkdfStubs;
-    type HmacSha256 = HmacStubs;
-    type HkdfSha512 = HkdfStubs;
-    type HmacSha512 = HmacStubs;
+    type HkdfSha256 = hkdf::Hkdf<Sha256>;
+    type HmacSha256 = hmac::HmacSha256;
+    type HkdfSha512 = hkdf::Hkdf<Sha512>;
+    type HmacSha512 = hmac::HmacSha512;
     type AesCbcPkcs7Padded = AesCbcPkcs7PaddedStubs;
     type X25519 = X25519Stubs;
     type P256 = P256Stubs;
@@ -47,9 +55,24 @@
     type AesCtr128 = Aes128Stubs;
     type AesCtr256 = Aes256Stubs;
     type Ed25519 = Ed25519Stubs;
-    type CryptoRng = ();
+    type CryptoRng = BoringSslRng;
 
     fn constant_time_eq(_a: &[u8], _b: &[u8]) -> bool {
         unimplemented!()
     }
 }
+
+/// OpenSSL implemented random number generator
+pub struct BoringSslRng;
+
+impl CryptoRng for BoringSslRng {
+    fn new() -> Self {
+        BoringSslRng {}
+    }
+
+    fn next_u64(&mut self) -> u64 {
+        let mut buf = [0; 8];
+        bssl_crypto::rand::rand_bytes(&mut buf);
+        u64::from_be_bytes(buf)
+    }
+}
diff --git a/nearby/crypto/crypto_provider_openssl/src/hkdf_boringssl.rs b/nearby/crypto/crypto_provider_openssl/src/hkdf_boringssl.rs
index 63e0ebc..f6c106d 100644
--- a/nearby/crypto/crypto_provider_openssl/src/hkdf_boringssl.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/hkdf_boringssl.rs
@@ -23,7 +23,6 @@
 use std::marker::PhantomData;
 
 /// openssl based hkdf implementation
-#[derive(Clone)]
 pub struct Hkdf<H: OpenSslHash> {
     _marker: PhantomData<H>,
     salt: Option<Vec<u8>>,
@@ -63,3 +62,15 @@
         self.expand_multi_info(&[info], okm)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::Openssl;
+    use core::marker::PhantomData;
+    use crypto_provider::hkdf::testing::*;
+
+    #[apply(hkdf_test_cases)]
+    fn hkdf_tests(testcase: CryptoProviderTestCase<Openssl>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs b/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs
index b6885bc..605cff1 100644
--- a/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs
@@ -17,7 +17,6 @@
 use std::marker::PhantomData;
 
 /// openssl based hkdf implementation
-#[derive(Clone)]
 pub struct Hkdf<H: OpenSslHash> {
     _marker: PhantomData<H>,
     salt: Option<Vec<u8>>,
@@ -61,3 +60,15 @@
         self.expand_multi_info(&[info], okm)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::Openssl;
+    use core::marker::PhantomData;
+    use crypto_provider::hkdf::testing::*;
+
+    #[apply(hkdf_test_cases)]
+    fn hkdf_tests(testcase: CryptoProviderTestCase<Openssl>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs b/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs
index 82782b9..af728b3 100644
--- a/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs
@@ -97,3 +97,15 @@
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::Openssl;
+    use core::marker::PhantomData;
+    use crypto_provider::hmac::testing::*;
+
+    #[apply(hmac_test_cases)]
+    fn hmac_tests(testcase: CryptoProviderTestCase<Openssl>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_openssl/src/hmac_openssl.rs b/nearby/crypto/crypto_provider_openssl/src/hmac_openssl.rs
index 34a64c4..d99ee3e 100644
--- a/nearby/crypto/crypto_provider_openssl/src/hmac_openssl.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/hmac_openssl.rs
@@ -175,3 +175,15 @@
         Err(MacError)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::Openssl;
+    use core::marker::PhantomData;
+    use crypto_provider::hmac::testing::*;
+
+    #[apply(hmac_test_cases)]
+    fn hmac_tests(testcase: CryptoProviderTestCase<Openssl>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
index ad5a4b8..2ab5354 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
+++ b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
@@ -14,9 +14,8 @@
 x25519-dalek.workspace = true
 p256 = { workspace = true, features = ["ecdh"], default-features = false }
 sec1.workspace = true
-ed25519-dalek = { workspace = true, default-features = false }
+ed25519-dalek = { workspace = true, default-features = false, features = ["rand_core"] }
 rand = { workspace = true, default-features = false }
-rand_core_05_adapter.workspace = true
 rand_core.workspace = true
 subtle.workspace = true
 aes.workspace = true
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
index 874aa82..df5c5de 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
@@ -12,30 +12,33 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use ed25519_dalek::Signer;
+
 use crypto_provider::ed25519::{
     InvalidBytes, InvalidSignature, Signature as _, SignatureError, KEY_LENGTH, KEY_PAIR_LENGTH,
     SIGNATURE_LENGTH,
 };
-use ed25519_dalek::Signer;
 
 pub struct Ed25519;
+
 impl crypto_provider::ed25519::Ed25519Provider for Ed25519 {
     type KeyPair = KeyPair;
     type PublicKey = PublicKey;
     type Signature = Signature;
 }
 
-pub struct KeyPair(ed25519_dalek::Keypair);
+pub struct KeyPair(ed25519_dalek::SigningKey);
+
 impl crypto_provider::ed25519::KeyPair for KeyPair {
     type PublicKey = PublicKey;
     type Signature = Signature;
 
     fn to_bytes(&self) -> [u8; KEY_PAIR_LENGTH] {
-        self.0.to_bytes()
+        self.0.to_keypair_bytes()
     }
 
     fn from_bytes(bytes: [u8; KEY_PAIR_LENGTH]) -> Result<Self, InvalidBytes> {
-        ed25519_dalek::Keypair::from_bytes(&bytes)
+        ed25519_dalek::SigningKey::from_keypair_bytes(&bytes)
             .map(Self)
             .map_err(|_| InvalidBytes)
     }
@@ -51,23 +54,22 @@
     #[cfg(feature = "std")]
     fn generate() -> Self {
         let mut csprng = rand::rngs::ThreadRng::default();
-        Self(ed25519_dalek::Keypair::generate(
-            &mut rand_core_05_adapter::RandWrapper::from(&mut csprng),
-        ))
+        Self(ed25519_dalek::SigningKey::generate(&mut csprng))
     }
 
     fn public(&self) -> Self::PublicKey {
-        PublicKey(self.0.public)
+        PublicKey(self.0.verifying_key())
     }
 }
 
 pub struct Signature(ed25519_dalek::Signature);
+
 impl crypto_provider::ed25519::Signature for Signature {
     fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidSignature> {
         if bytes.len() != SIGNATURE_LENGTH {
             return Err(InvalidSignature);
         }
-        ed25519_dalek::Signature::from_bytes(bytes)
+        ed25519_dalek::Signature::from_slice(bytes)
             .map(Self)
             .map_err(|_| InvalidSignature)
     }
@@ -77,7 +79,8 @@
     }
 }
 
-pub struct PublicKey(ed25519_dalek::PublicKey);
+pub struct PublicKey(ed25519_dalek::VerifyingKey);
+
 impl crypto_provider::ed25519::PublicKey for PublicKey {
     type Signature = Signature;
 
@@ -85,7 +88,7 @@
     where
         Self: Sized,
     {
-        ed25519_dalek::PublicKey::from_bytes(&bytes)
+        ed25519_dalek::VerifyingKey::from_bytes(&bytes)
             .map(PublicKey)
             .map_err(|_| InvalidBytes)
     }
@@ -107,9 +110,10 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::ed25519::Ed25519;
     use crypto_provider::ed25519::testing::{run_rfc_test_vectors, run_wycheproof_test_vectors};
 
+    use crate::ed25519::Ed25519;
+
     #[test]
     fn wycheproof_test_ed25519_rustcrypto() {
         run_wycheproof_test_vectors::<Ed25519>()
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs
index d6ca687..8ff5d7b 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs
@@ -22,7 +22,6 @@
 use hmac::digest::{HashMarker, OutputSizeUser};
 
 /// RustCrypto based hkdf implementation
-#[derive(Clone)]
 pub struct Hkdf<D>
 where
     D: OutputSizeUser,
@@ -72,3 +71,15 @@
         self.hkdf_impl.expand(info, okm).map_err(|_| InvalidLength)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::RustCrypto;
+    use core::marker::PhantomData;
+    use crypto_provider::hkdf::testing::*;
+
+    #[apply(hkdf_test_cases)]
+    fn hkdf_tests(testcase: CryptoProviderTestCase<RustCrypto>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs
index e31b815..95254a5 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs
@@ -112,3 +112,15 @@
             .map_err(|_| MacError)
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::RustCrypto;
+    use core::marker::PhantomData;
+    use crypto_provider::hmac::testing::*;
+
+    #[apply(hmac_test_cases)]
+    fn hmac_tests(testcase: CryptoProviderTestCase<RustCrypto>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
index 9807f81..9145233 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
@@ -65,7 +65,7 @@
 }
 
 impl<R: CryptoRng + SeedableRng + RngCore> RustCryptoImpl<R> {
-    ///
+    /// Create a new instance of RustCrypto
     pub fn new() -> Self {
         Self {
             _marker: Default::default(),
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs b/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
index a184d44..794d780 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
@@ -48,7 +48,7 @@
 
     fn generate_random(rng: &mut Self::Rng) -> Self {
         Self {
-            secret: x25519_dalek::EphemeralSecret::new(&mut rng.0),
+            secret: x25519_dalek::EphemeralSecret::random_from_rng(&mut rng.0),
             marker: Default::default(),
         }
     }
@@ -76,9 +76,11 @@
         _public_key: &X25519PublicKey,
     ) -> Result<Self, Self::Error> {
         Ok(Self {
-            secret: x25519_dalek::EphemeralSecret::new(&mut crate::testing::MockCryptoRng {
-                values: private_bytes.iter(),
-            }),
+            secret: x25519_dalek::EphemeralSecret::random_from_rng(
+                &mut crate::testing::MockCryptoRng {
+                    values: private_bytes.iter(),
+                },
+            ),
             marker: Default::default(),
         })
     }
diff --git a/nearby/presence/ldt/benches/ldt_scan.rs b/nearby/presence/ldt/benches/ldt_scan.rs
index 8088869..31f669f 100644
--- a/nearby/presence/ldt/benches/ldt_scan.rs
+++ b/nearby/presence/ldt/benches/ldt_scan.rs
@@ -15,7 +15,9 @@
 use criterion::{black_box, criterion_group, criterion_main, Criterion};
 use crypto_provider_rustcrypto::RustCrypto;
 use ctr::cipher::{KeyIvInit as _, StreamCipher as _, StreamCipherSeek as _};
-use ldt::{DefaultPadder, Ldt, LdtKey, Mix, Padder, Swap, XorPadder};
+use ldt::{
+    DefaultPadder, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Mix, Padder, Swap, XorPadder,
+};
 use ldt_tbc::TweakableBlockCipher;
 use rand::SeedableRng as _;
 use sha2::Digest as _;
@@ -180,7 +182,8 @@
 /// A wrapper that lets us avoid percolating the need to specify a bogus and type-confused padder
 /// for ciphers that don't use one.
 struct LdtScanCipher<const B: usize, T: TweakableBlockCipher<B>, M: Mix, P: Padder<B, T>> {
-    ldt: Ldt<B, T, M>,
+    ldt_enc: LdtEncryptCipher<B, T, M>,
+    ldt_dec: LdtDecryptCipher<B, T, M>,
     padder: P,
 }
 
@@ -188,11 +191,11 @@
     for LdtScanCipher<B, T, M, P>
 {
     fn encrypt(&mut self, buf: &mut [u8]) {
-        self.ldt.encrypt(buf, &self.padder).unwrap();
+        self.ldt_enc.encrypt(buf, &self.padder).unwrap();
     }
 
     fn decrypt(&mut self, buf: &mut [u8]) {
-        self.ldt.decrypt(buf, &self.padder).unwrap();
+        self.ldt_dec.decrypt(buf, &self.padder).unwrap();
     }
 }
 
@@ -231,7 +234,8 @@
     fn build_cipher<R: rand::Rng + rand::CryptoRng>(&self, key_rng: &mut R) -> Self::Cipher {
         let key: LdtKey<T::Key> = LdtKey::from_random(key_rng);
         LdtScanCipher {
-            ldt: Ldt::new(&key),
+            ldt_enc: LdtEncryptCipher::new(&key),
+            ldt_dec: LdtDecryptCipher::new(&key),
             padder: P::generate(key_rng),
         }
     }
diff --git a/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs b/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs
index f579fe0..1b6af2d 100644
--- a/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs
+++ b/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs
@@ -15,7 +15,7 @@
 use crypto_provider::aes;
 use crypto_provider::aes::BLOCK_SIZE;
 use crypto_provider_rustcrypto::RustCrypto;
-use ldt::{Ldt, LdtKey, Swap, XorPadder};
+use ldt::{LdtEncryptCipher, LdtKey, Swap, XorPadder};
 use rand::{Rng as _, SeedableRng as _};
 use rand_ext::*;
 use serde_json::json;
@@ -31,10 +31,11 @@
         let key = LdtKey::from_random(&mut rng);
         let pad_xor: [u8; aes::BLOCK_SIZE] = random_bytes(&mut rng);
 
-        let ldt = Ldt::<BLOCK_SIZE, XtsAes128<RustCrypto>, Swap>::new(&key);
+        let ldt_enc = LdtEncryptCipher::<BLOCK_SIZE, XtsAes128<RustCrypto>, Swap>::new(&key);
 
         let mut ciphertext = plaintext.clone();
-        ldt.encrypt(&mut ciphertext, &XorPadder::from(pad_xor))
+        ldt_enc
+            .encrypt(&mut ciphertext, &XorPadder::from(pad_xor))
             .unwrap();
 
         array.push(json!({
diff --git a/nearby/presence/ldt/examples/ldt_benchmark.rs b/nearby/presence/ldt/examples/ldt_benchmark.rs
index 7ab41ad..f6793e1 100644
--- a/nearby/presence/ldt/examples/ldt_benchmark.rs
+++ b/nearby/presence/ldt/examples/ldt_benchmark.rs
@@ -16,7 +16,7 @@
 
 use clap::Parser as _;
 use crypto_provider_rustcrypto::RustCrypto;
-use ldt::{Ldt, LdtKey, Mix, Swap, XorPadder};
+use ldt::{LdtDecryptCipher, LdtEncryptCipher, LdtKey, Mix, Swap, XorPadder};
 
 use ldt_tbc::TweakableBlockCipher;
 use rand::{distributions, seq::SliceRandom, Rng as _, SeedableRng as _};
@@ -42,7 +42,7 @@
         .iter()
         .map(|s| {
             let mut ciphertext = s.plaintext.clone();
-            s.ldt.encrypt(&mut ciphertext[..], &padder).unwrap();
+            s.ldt_enc.encrypt(&mut ciphertext[..], &padder).unwrap();
             ciphertext
         })
         .collect::<Vec<_>>();
@@ -71,7 +71,7 @@
 
                 buf.clear();
                 buf.extend_from_slice(ciphertext.as_slice());
-                scenario.ldt.decrypt(&mut buf, &padder).unwrap();
+                scenario.ldt_dec.decrypt(&mut buf, &padder).unwrap();
 
                 hasher.update(&buf[..MATCH_LEN]);
                 hasher.finalize_into_reset(&mut hash_output);
@@ -127,7 +127,8 @@
 const MATCH_LEN: usize = 16;
 
 struct LdtScenario<const B: usize, T: TweakableBlockCipher<B>, M: Mix> {
-    ldt: Ldt<B, T, M>,
+    ldt_enc: LdtEncryptCipher<B, T, M>,
+    ldt_dec: LdtDecryptCipher<B, T, M>,
     plaintext: Vec<u8>,
     plaintext_prefix_hash: [u8; 32],
 }
@@ -142,7 +143,8 @@
     plaintext_len: usize,
 ) -> LdtScenario<B, T, M> {
     let ldt_key: LdtKey<T::Key> = LdtKey::from_random(rng);
-    let ldt: Ldt<B, T, M> = Ldt::new(&ldt_key);
+    let ldt_enc = LdtEncryptCipher::new(&ldt_key);
+    let ldt_dec = LdtDecryptCipher::new(&ldt_key);
     let plaintext = random_vec(rng, plaintext_len);
 
     let mut hasher = sha2::Sha256::new();
@@ -151,7 +153,8 @@
     hasher.finalize_into_reset(&mut plaintext_prefix_hash);
 
     LdtScenario {
-        ldt,
+        ldt_enc,
+        ldt_dec,
         plaintext,
         plaintext_prefix_hash: plaintext_prefix_hash.into(),
     }
diff --git a/nearby/presence/ldt/examples/ldt_prp.rs b/nearby/presence/ldt/examples/ldt_prp.rs
index c744b81..0e7bcf6 100644
--- a/nearby/presence/ldt/examples/ldt_prp.rs
+++ b/nearby/presence/ldt/examples/ldt_prp.rs
@@ -43,14 +43,24 @@
     for _ in 0..args.trials {
         let (percent, ok) = if rng.gen() {
             do_trial(
-                Ldt::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_random(&mut rng)),
+                LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_random(
+                    &mut rng,
+                )),
+                LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_random(
+                    &mut rng,
+                )),
                 &mut rng,
                 DefaultPadder::default(),
                 &args,
             )
         } else {
             do_trial(
-                Ldt::<16, XtsAes256<RustCrypto>, Swap>::new(&LdtKey::from_random(&mut rng)),
+                LdtEncryptCipher::<16, XtsAes256<RustCrypto>, Swap>::new(&LdtKey::from_random(
+                    &mut rng,
+                )),
+                LdtDecryptCipher::<16, XtsAes256<RustCrypto>, Swap>::new(&LdtKey::from_random(
+                    &mut rng,
+                )),
                 &mut rng,
                 DefaultPadder::default(),
                 &args,
@@ -87,7 +97,8 @@
 }
 
 fn do_trial<const B: usize, T: TweakableBlockCipher<B>, P: Padder<B, T>, M: Mix, R: rand::Rng>(
-    ldt: Ldt<B, T, M>,
+    ldt_enc: LdtEncryptCipher<B, T, M>,
+    ldt_dec: LdtDecryptCipher<B, T, M>,
     rng: &mut R,
     padder: P,
     args: &Args,
@@ -97,12 +108,12 @@
     let plaintext = random_vec(rng, len);
 
     let mut ciphertext = plaintext.clone();
-    ldt.encrypt(&mut ciphertext, &padder).unwrap();
+    ldt_enc.encrypt(&mut ciphertext, &padder).unwrap();
 
     // flip a random bit
     ciphertext[rng.gen_range(0..len)] ^= 1 << rng.gen_range(0..8);
 
-    ldt.decrypt(&mut ciphertext, &padder).unwrap();
+    ldt_dec.decrypt(&mut ciphertext, &padder).unwrap();
     assert_ne!(plaintext, ciphertext);
 
     let differing_bits: u32 = plaintext
diff --git a/nearby/presence/ldt/fuzz/Cargo.lock b/nearby/presence/ldt/fuzz/Cargo.lock
index c952332..d0a7fc3 100644
--- a/nearby/presence/ldt/fuzz/Cargo.lock
+++ b/nearby/presence/ldt/fuzz/Cargo.lock
@@ -60,15 +60,6 @@
 
 [[package]]
 name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "block-buffer"
 version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
@@ -86,12 +77,6 @@
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
 name = "bytes"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -153,7 +138,7 @@
 checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
  "zeroize",
 ]
@@ -165,7 +150,7 @@
 checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "typenum",
 ]
 
@@ -193,10 +178,9 @@
  "p256",
  "rand",
  "rand_chacha",
- "rand_core 0.6.4",
- "rand_core_05_adapter",
+ "rand_core",
  "sec1",
- "sha2 0.10.6",
+ "sha2",
  "subtle",
  "x25519-dalek",
 ]
@@ -212,15 +196,16 @@
 
 [[package]]
 name = "curve25519-dalek"
-version = "3.2.0"
+version = "4.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
+checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585"
 dependencies = [
- "byteorder",
- "digest 0.9.0",
- "rand_core 0.5.1",
+ "cfg-if",
+ "digest",
+ "fiat-crypto",
+ "packed_simd_2",
+ "platforms",
  "subtle",
- "zeroize",
 ]
 
 [[package]]
@@ -246,43 +231,34 @@
 
 [[package]]
 name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "digest"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
- "block-buffer 0.10.4",
+ "block-buffer",
  "crypto-common",
  "subtle",
 ]
 
 [[package]]
 name = "ed25519"
-version = "1.5.3"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
 dependencies = [
  "signature",
 ]
 
 [[package]]
 name = "ed25519-dalek"
-version = "1.0.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a"
 dependencies = [
  "curve25519-dalek",
  "ed25519",
- "sha2 0.9.9",
- "zeroize",
+ "rand_core",
+ "sha2",
 ]
 
 [[package]]
@@ -293,12 +269,12 @@
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "digest 0.10.6",
+ "digest",
  "ff",
  "generic-array",
  "group",
  "hkdf",
- "rand_core 0.6.4",
+ "rand_core",
  "sec1",
  "subtle",
  "zeroize",
@@ -310,11 +286,17 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
 dependencies = [
- "rand_core 0.6.4",
+ "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.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -343,7 +325,7 @@
 checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
 dependencies = [
  "ff",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
 ]
 
@@ -362,7 +344,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
@@ -428,6 +410,12 @@
 ]
 
 [[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
+[[package]]
 name = "once_cell"
 version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -450,6 +438,22 @@
 ]
 
 [[package]]
+name = "packed_simd_2"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
+dependencies = [
+ "cfg-if",
+ "libm",
+]
+
+[[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.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -500,7 +504,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
@@ -510,17 +514,11 @@
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-
-[[package]]
-name = "rand_core"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
@@ -529,14 +527,6 @@
 ]
 
 [[package]]
-name = "rand_core_05_adapter"
-version = "0.1.0"
-dependencies = [
- "rand",
- "rand_core 0.5.1",
-]
-
-[[package]]
 name = "sec1"
 version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -551,33 +541,20 @@
 
 [[package]]
 name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
-
-[[package]]
-name = "sha2"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
 name = "signature"
-version = "1.6.4"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
 
 [[package]]
 name = "subtle"
@@ -597,18 +574,6 @@
 ]
 
 [[package]]
-name = "synstructure"
-version = "0.12.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "unicode-xid",
-]
-
-[[package]]
 name = "typenum"
 version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -621,12 +586,6 @@
 checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
 
 [[package]]
-name = "unicode-xid"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
-
-[[package]]
 name = "universal-hash"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -650,13 +609,12 @@
 
 [[package]]
 name = "x25519-dalek"
-version = "2.0.0-pre.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df"
+checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95"
 dependencies = [
  "curve25519-dalek",
- "rand_core 0.6.4",
- "zeroize",
+ "rand_core",
 ]
 
 [[package]]
@@ -673,18 +631,3 @@
 version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
diff --git a/nearby/presence/ldt/fuzz/fuzz_targets/ldt_roundtrip.rs b/nearby/presence/ldt/fuzz/fuzz_targets/ldt_roundtrip.rs
index 16a06c5..13e2a46 100644
--- a/nearby/presence/ldt/fuzz/fuzz_targets/ldt_roundtrip.rs
+++ b/nearby/presence/ldt/fuzz/fuzz_targets/ldt_roundtrip.rs
@@ -19,14 +19,16 @@
 use xts_aes::XtsAes128;
 
 fuzz_target!(|data: LdtFuzzInput| {
-    let ldt =
-        Ldt::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_concatenated(&data.ldt_key));
+    let ldt_enc =
+        LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_concatenated(&data.ldt_key));
+    let ldt_dec =
+        LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_concatenated(&data.ldt_key));
     let len = 16 + (data.len as usize % 16);
     let padder: XorPadder<16> = data.xor_padder.clone().into();
 
     let mut buffer = data.plaintext.clone();
-    ldt.encrypt(&mut buffer[..len], &padder).unwrap();
-    ldt.decrypt(&mut buffer[..len], &padder).unwrap();
+    ldt_enc.encrypt(&mut buffer[..len], &padder).unwrap();
+    ldt_dec.decrypt(&mut buffer[..len], &padder).unwrap();
     assert_eq!(data.plaintext, buffer);
 });
 
diff --git a/nearby/presence/ldt/src/lib.rs b/nearby/presence/ldt/src/lib.rs
index 9ea8b79..8dc4068 100644
--- a/nearby/presence/ldt/src/lib.rs
+++ b/nearby/presence/ldt/src/lib.rs
@@ -17,7 +17,6 @@
 #![no_std]
 #![forbid(unsafe_code)]
 #![deny(
-    missing_docs,
     clippy::indexing_slicing,
     clippy::unwrap_used,
     clippy::panic,
@@ -26,24 +25,27 @@
 
 use core::{fmt, marker::PhantomData};
 use ldt_tbc::{ConcatenatedKeyArray, TweakableBlockCipher, TweakableBlockCipherKey};
+use ldt_tbc::{TweakableBlockCipherDecrypter, TweakableBlockCipherEncrypter};
 
-/// Implementation of the [LDT](https://eprint.iacr.org/2017/841.pdf) length doubler.
+/// Implementation of the [LDT](https://eprint.iacr.org/2017/841.pdf) length doubler encryption cipher.
 ///
 /// `B` is the block size.
+/// `T` is the provided implementation of a Tweakable Block Cipher
+/// `M` is the implementation of a [pure mix function](https://eprint.iacr.org/2017/841.pdf)
 #[repr(C)]
-pub struct Ldt<const B: usize, T: TweakableBlockCipher<B>, M: Mix> {
-    cipher_1: T,
-    cipher_2: T,
+pub struct LdtEncryptCipher<const B: usize, T: TweakableBlockCipher<B>, M: Mix> {
+    cipher_1: T::EncryptionCipher,
+    cipher_2: T::EncryptionCipher,
     // marker to use `M`
     mix_phantom: PhantomData<M>,
 }
 
-impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> Ldt<B, T, M> {
-    /// Create an [Ldt] with the provided Tweakable block cipher and Mix function
+impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> LdtEncryptCipher<B, T, M> {
+    /// Create an [LdtEncryptCipher] with the provided Tweakable block cipher and Mix function
     pub fn new(key: &LdtKey<T::Key>) -> Self {
-        Ldt {
-            cipher_1: T::new(&key.key_1),
-            cipher_2: T::new(&key.key_2),
+        LdtEncryptCipher {
+            cipher_1: T::EncryptionCipher::new(&key.key_1),
+            cipher_2: T::EncryptionCipher::new(&key.key_2),
             mix_phantom: PhantomData::default(),
         }
     }
@@ -55,7 +57,7 @@
     /// # Errors
     /// - if `data` has a length outside of `[B, B * 2)`.
     pub fn encrypt<P: Padder<B, T>>(&self, data: &mut [u8], padder: &P) -> Result<(), LdtError> {
-        self.do_ldt(
+        do_ldt::<B, T, M, _, _, _, P>(
             data,
             |cipher, tweak, block| cipher.encrypt(tweak, block),
             padder,
@@ -64,6 +66,30 @@
             &self.cipher_2,
         )
     }
+}
+
+/// Implementation of the [LDT](https://eprint.iacr.org/2017/841.pdf) length doubler decryption cipher.
+///
+/// `B` is the block size.
+/// `T` is the provided implementation of a Tweakable Block Cipher
+/// `M` is the implementation of a [pure mix function](https://eprint.iacr.org/2017/841.pdf)
+#[repr(C)]
+pub struct LdtDecryptCipher<const B: usize, T: TweakableBlockCipher<B>, M: Mix> {
+    cipher_1: T::DecryptionCipher,
+    cipher_2: T::DecryptionCipher,
+    // marker to use `M`
+    mix_phantom: PhantomData<M>,
+}
+
+impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> LdtDecryptCipher<B, T, M> {
+    /// Create an [LdtDecryptCipher] with the provided Tweakable block cipher and Mix function
+    pub fn new(key: &LdtKey<T::Key>) -> Self {
+        LdtDecryptCipher {
+            cipher_1: T::DecryptionCipher::new(&key.key_1),
+            cipher_2: T::DecryptionCipher::new(&key.key_2),
+            mix_phantom: PhantomData::default(),
+        }
+    }
 
     /// Decrypt `data` in place, performing the pad operation with `padder`.
     ///
@@ -72,7 +98,7 @@
     /// # Errors
     /// - if `data` has a length outside of `[B, B * 2)`.
     pub fn decrypt<P: Padder<B, T>>(&self, data: &mut [u8], padder: &P) -> Result<(), LdtError> {
-        self.do_ldt(
+        do_ldt::<B, T, M, _, _, _, P>(
             data,
             |cipher, tweak, block| cipher.decrypt(tweak, block),
             padder,
@@ -82,63 +108,66 @@
             &self.cipher_1,
         )
     }
+}
 
-    fn do_ldt<C, X, P>(
-        &self,
-        data: &mut [u8],
-        cipher_op: C,
-        padder: &P,
-        mix: X,
-        first_cipher: &T,
-        second_cipher: &T,
-    ) -> Result<(), LdtError>
-    where
-        // Encrypt or decrypt in place with a tweak
-        C: Fn(&T, T::Tweak, &mut [u8; B]),
-        // Mix a/b into block-sized chunks
-        X: Fn(&[u8], &[u8]) -> ([u8; B], [u8; B]),
-        P: Padder<B, T>,
-    {
-        if data.len() < B || data.len() >= B * 2 {
-            return Err(LdtError::InvalidLength(data.len()));
-        }
-        let s = data.len() - B;
-        debug_assert!(s < B);
-
-        // m1 length B, m2 length s (s < B)
-        let (m1, m2) = data.split_at(B);
-        debug_assert_eq!(s, m2.len());
-        let m1_ciphertext = {
-            let mut m1_plaintext = [0_u8; B];
-            // m1 is of length B, so no panic
-            m1_plaintext[..].copy_from_slice(m1);
-            let tweak = padder.pad_tweak(m2);
-            cipher_op(first_cipher, tweak, &mut m1_plaintext);
-            m1_plaintext
-        };
-        // |z| = B - s, |m3| = s
-        let (z, m3) = m1_ciphertext.split_at(B - s);
-        debug_assert_eq!(s, m3.len());
-        // c3 and c2 are the last s bytes of their size-B arrays, respectively
-        let (mut c3, c2) = mix(m3, m2);
-        let c1 = {
-            // constructing z || c3 is easy since c3 is already the last s bytes
-            c3[0..(B - s)].copy_from_slice(z);
-            let mut z_c3 = c3;
-            let tweak = padder.pad_tweak(&c2[B - s..]);
-            cipher_op(second_cipher, tweak, &mut z_c3);
-            z_c3
-        };
-        let len = data.len();
-        data.get_mut(0..B)
-            .ok_or(LdtError::InvalidLength(len))?
-            .copy_from_slice(&c1);
-        data.get_mut(B..)
-            .ok_or(LdtError::InvalidLength(len))?
-            .copy_from_slice(&c2[B - s..]);
-
-        Ok(())
+// internal implementation of ldt cipher operations, re-used by encryption and decryption, by providing
+// the corresponding cipher_op and mix operation
+fn do_ldt<const B: usize, T, M, O, C, X, P>(
+    data: &mut [u8],
+    cipher_op: O,
+    padder: &P,
+    mix: X,
+    first_cipher: &C,
+    second_cipher: &C,
+) -> Result<(), LdtError>
+where
+    T: TweakableBlockCipher<B>,
+    M: Mix,
+    // Encrypt or decrypt in place with a tweak
+    O: Fn(&C, T::Tweak, &mut [u8; B]),
+    // Mix a/b into block-sized chunks
+    X: Fn(&[u8], &[u8]) -> ([u8; B], [u8; B]),
+    P: Padder<B, T>,
+{
+    if data.len() < B || data.len() >= B * 2 {
+        return Err(LdtError::InvalidLength(data.len()));
     }
+    let s = data.len() - B;
+    debug_assert!(s < B);
+
+    // m1 length B, m2 length s (s < B)
+    let (m1, m2) = data.split_at(B);
+    debug_assert_eq!(s, m2.len());
+    let m1_ciphertext = {
+        let mut m1_plaintext = [0_u8; B];
+        // m1 is of length B, so no panic
+        m1_plaintext[..].copy_from_slice(m1);
+        let tweak = padder.pad_tweak(m2);
+        cipher_op(first_cipher, tweak, &mut m1_plaintext);
+        m1_plaintext
+    };
+    // |z| = B - s, |m3| = s
+    let (z, m3) = m1_ciphertext.split_at(B - s);
+    debug_assert_eq!(s, m3.len());
+    // c3 and c2 are the last s bytes of their size-B arrays, respectively
+    let (mut c3, c2) = mix(m3, m2);
+    let c1 = {
+        // constructing z || c3 is easy since c3 is already the last s bytes
+        c3[0..(B - s)].copy_from_slice(z);
+        let mut z_c3 = c3;
+        let tweak = padder.pad_tweak(&c2[B - s..]);
+        cipher_op(second_cipher, tweak, &mut z_c3);
+        z_c3
+    };
+    let len = data.len();
+    data.get_mut(0..B)
+        .ok_or(LdtError::InvalidLength(len))?
+        .copy_from_slice(&c1);
+    data.get_mut(B..)
+        .ok_or(LdtError::InvalidLength(len))?
+        .copy_from_slice(&c2[B - s..]);
+
+    Ok(())
 }
 
 /// Errors produced by LDT encryption/decryption.
diff --git a/nearby/presence/ldt/tests/ldt_roundtrip.rs b/nearby/presence/ldt/tests/ldt_roundtrip.rs
index b848984..b225399 100644
--- a/nearby/presence/ldt/tests/ldt_roundtrip.rs
+++ b/nearby/presence/ldt/tests/ldt_roundtrip.rs
@@ -27,15 +27,19 @@
 
     for _ in 0..100_000 {
         if rng.gen() {
+            let ldt_key = LdtKey::from_random(&mut rng);
             do_roundtrip(
-                Ldt::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_random(&mut rng)),
+                LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&ldt_key),
+                LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&ldt_key),
                 &DefaultPadder::default(),
                 &mut rng,
                 &plaintext_len_range,
             )
         } else {
+            let ldt_key = LdtKey::from_random(&mut rng);
             do_roundtrip(
-                Ldt::<16, XtsAes256<RustCrypto>, Swap>::new(&LdtKey::from_random(&mut rng)),
+                LdtEncryptCipher::<16, XtsAes256<RustCrypto>, Swap>::new(&ldt_key),
+                LdtDecryptCipher::<16, XtsAes256<RustCrypto>, Swap>::new(&ldt_key),
                 &DefaultPadder::default(),
                 &mut rng,
                 &plaintext_len_range,
@@ -47,22 +51,27 @@
 #[test]
 fn roundtrip_xor_padder() {
     let mut rng = rand::rngs::StdRng::from_entropy();
-    // 2 bytes smaller becauwe're using a 2 byte salt
+    // 2 bytes smaller because we're using a 2 byte salt
     let plaintext_len_range =
         distributions::Uniform::new_inclusive(BLOCK_SIZE, BLOCK_SIZE * 2 - 1 - 2);
 
     for _ in 0..100_000 {
         let padder: XorPadder<BLOCK_SIZE> = random_bytes(&mut rng).into();
+
         if rng.gen() {
+            let ldt_key = LdtKey::from_random(&mut rng);
             do_roundtrip(
-                Ldt::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_random(&mut rng)),
+                LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&ldt_key),
+                LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&ldt_key),
                 &padder,
                 &mut rng,
                 &plaintext_len_range,
             )
         } else {
+            let ldt_key = LdtKey::from_random(&mut rng);
             do_roundtrip(
-                Ldt::<16, XtsAes256<RustCrypto>, Swap>::new(&LdtKey::from_random(&mut rng)),
+                LdtEncryptCipher::<16, XtsAes256<RustCrypto>, Swap>::new(&ldt_key),
+                LdtDecryptCipher::<16, XtsAes256<RustCrypto>, Swap>::new(&ldt_key),
                 &padder,
                 &mut rng,
                 &plaintext_len_range,
@@ -78,7 +87,8 @@
     M: Mix,
     R: rand::Rng,
 >(
-    ldt: Ldt<B, T, M>,
+    ldt_enc: LdtEncryptCipher<B, T, M>,
+    ldt_dec: LdtDecryptCipher<B, T, M>,
     padder: &P,
     rng: &mut R,
     plaintext_len_range: &distributions::Uniform<usize>,
@@ -87,11 +97,11 @@
     let plaintext = random_vec(rng, len);
 
     let mut ciphertext = plaintext.clone();
-    ldt.encrypt(&mut ciphertext, padder).unwrap();
+    ldt_enc.encrypt(&mut ciphertext, padder).unwrap();
 
     assert_eq!(plaintext.len(), ciphertext.len());
     assert_ne!(plaintext, ciphertext);
 
-    ldt.decrypt(&mut ciphertext, padder).unwrap();
+    ldt_dec.decrypt(&mut ciphertext, padder).unwrap();
     assert_eq!(plaintext, ciphertext);
 }
diff --git a/nearby/presence/ldt/tests/ldt_test_vectors.rs b/nearby/presence/ldt/tests/ldt_test_vectors.rs
index ff2c6fe..691bd62 100644
--- a/nearby/presence/ldt/tests/ldt_test_vectors.rs
+++ b/nearby/presence/ldt/tests/ldt_test_vectors.rs
@@ -14,7 +14,7 @@
 
 use anyhow::anyhow;
 use crypto_provider_rustcrypto::RustCrypto;
-use ldt::{DefaultPadder, Ldt, LdtKey, Swap, XorPadder};
+use ldt::{DefaultPadder, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Swap, XorPadder};
 use std::{fs, io::Read as _};
 use test_helper::{extract_key_array, extract_key_vec};
 use xts_aes::XtsAes128;
@@ -46,17 +46,24 @@
         assert!(len >= crypto_provider::aes::BLOCK_SIZE);
         assert!(len < crypto_provider::aes::BLOCK_SIZE * 2);
 
-        let ldt = Ldt::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_concatenated(&key));
+        let ldt_enc = LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(
+            &LdtKey::from_concatenated(&key),
+        );
+        let ldt_dec = LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(
+            &LdtKey::from_concatenated(&key),
+        );
 
         let mut plaintext = [0; 31];
         plaintext[..len].copy_from_slice(&expected_ciphertext);
-        ldt.decrypt(&mut plaintext[..len], &DefaultPadder::default())
+        ldt_dec
+            .decrypt(&mut plaintext[..len], &DefaultPadder::default())
             .unwrap();
         assert_eq!(&expected_plaintext, &plaintext[..len]);
 
         let mut ciphertext = [0; 31];
         ciphertext[..len].copy_from_slice(&expected_plaintext);
-        ldt.encrypt(&mut ciphertext[..len], &DefaultPadder::default())
+        ldt_enc
+            .encrypt(&mut ciphertext[..len], &DefaultPadder::default())
             .unwrap();
         assert_eq!(&expected_ciphertext, &ciphertext[..len]);
     }
@@ -92,17 +99,24 @@
         assert!(len >= crypto_provider::aes::BLOCK_SIZE);
         assert!(len < crypto_provider::aes::BLOCK_SIZE * 2);
 
-        let ldt = Ldt::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_concatenated(&key));
+        let ldt_enc = LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(
+            &LdtKey::from_concatenated(&key),
+        );
+        let ldt_dec = LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(
+            &LdtKey::from_concatenated(&key),
+        );
 
         let mut plaintext = [0; 31];
         plaintext[..len].copy_from_slice(&expected_ciphertext);
-        ldt.decrypt(&mut plaintext[..len], &XorPadder::from(xor_pad))
+        ldt_dec
+            .decrypt(&mut plaintext[..len], &XorPadder::from(xor_pad))
             .unwrap();
         assert_eq!(&expected_plaintext, &plaintext[..len]);
 
         let mut ciphertext = [0; 31];
         ciphertext[..len].copy_from_slice(&expected_plaintext);
-        ldt.encrypt(&mut ciphertext[..len], &XorPadder::from(xor_pad))
+        ldt_enc
+            .encrypt(&mut ciphertext[..len], &XorPadder::from(xor_pad))
             .unwrap();
         assert_eq!(&expected_ciphertext, &ciphertext[..len]);
     }
diff --git a/nearby/presence/ldt/tests/tests.rs b/nearby/presence/ldt/tests/tests.rs
index 77dbb35..a50658d 100644
--- a/nearby/presence/ldt/tests/tests.rs
+++ b/nearby/presence/ldt/tests/tests.rs
@@ -17,15 +17,16 @@
 use alloc::vec;
 use crypto_provider::aes::BLOCK_SIZE;
 use crypto_provider_rustcrypto::RustCrypto;
-use ldt::{DefaultPadder, Ldt, LdtError, LdtKey, Padder, Swap, XorPadder};
+use ldt::{
+    DefaultPadder, LdtDecryptCipher, LdtEncryptCipher, LdtError, LdtKey, Padder, Swap, XorPadder,
+};
 use xts_aes::{XtsAes128, XtsAes128Key};
 
 #[test]
 fn normal_pad_empty() {
     let padder = DefaultPadder::default();
     let tweak: xts_aes::Tweak =
-        <DefaultPadder as Padder<16, xts_aes::XtsAes128<RustCrypto>>>::pad_tweak(&padder, &[]);
-
+        <DefaultPadder as Padder<16, XtsAes128<RustCrypto>>>::pad_tweak(&padder, &[]);
     let bytes = tweak.le_bytes();
 
     // leading 1 bit
@@ -38,7 +39,7 @@
 fn normal_pad_one_byte() {
     let padder = DefaultPadder::default();
     let tweak: xts_aes::Tweak =
-        <DefaultPadder as Padder<16, xts_aes::XtsAes128<RustCrypto>>>::pad_tweak(&padder, &[0x81]);
+        <DefaultPadder as Padder<16, XtsAes128<RustCrypto>>>::pad_tweak(&padder, &[0x81]);
 
     let bytes = tweak.le_bytes();
 
@@ -69,7 +70,7 @@
 fn normal_pad_too_big_panics() {
     let padder = DefaultPadder::default();
     let input = [0x99; 16];
-    <DefaultPadder as Padder<16, xts_aes::XtsAes128<RustCrypto>>>::pad_tweak(&padder, &input);
+    <DefaultPadder as Padder<16, XtsAes128<RustCrypto>>>::pad_tweak(&padder, &input);
 }
 
 #[test]
@@ -77,7 +78,7 @@
     let padder = [0x24; BLOCK_SIZE].into();
     let tweak: xts_aes::Tweak = <XorPadder<BLOCK_SIZE> as Padder<
         BLOCK_SIZE,
-        xts_aes::XtsAes128<RustCrypto>,
+        XtsAes128<RustCrypto>,
     >>::pad_tweak(&padder, &[]);
 
     let bytes = tweak.le_bytes();
@@ -135,41 +136,42 @@
 
 #[test]
 fn encrypt_too_short_err() {
-    do_length_check(7, |ldt, payload| {
-        ldt.encrypt(payload, &DefaultPadder::default())
-    })
+    do_length_check_enc(7)
 }
 
 #[test]
 fn encrypt_too_long_err() {
-    do_length_check(40, |ldt, payload| {
-        ldt.encrypt(payload, &DefaultPadder::default())
-    })
+    do_length_check_enc(40)
 }
 #[test]
 fn decrypt_too_short_err() {
-    do_length_check(7, |ldt, payload| {
-        ldt.decrypt(payload, &DefaultPadder::default())
-    })
+    do_length_check_dec(7)
 }
 #[test]
 fn decrypt_too_long_err() {
-    do_length_check(40, |ldt, payload| {
-        ldt.decrypt(payload, &DefaultPadder::default())
-    })
+    do_length_check_dec(40)
 }
 
-fn do_length_check<
-    F: Fn(Ldt<{ BLOCK_SIZE }, XtsAes128<RustCrypto>, Swap>, &mut [u8]) -> Result<(), LdtError>,
->(
-    payload_len: usize,
-    ldt_op: F,
-) {
-    let ldt = Ldt::new(&LdtKey::<XtsAes128Key>::from_concatenated(&[0u8; 64]));
+fn do_length_check_dec(len: usize) {
+    let ldt_dec = LdtDecryptCipher::<{ BLOCK_SIZE }, XtsAes128<RustCrypto>, Swap>::new(
+        &LdtKey::<XtsAes128Key>::from_concatenated(&[0u8; 64]),
+    );
 
-    let mut payload = vec![0; payload_len];
+    let mut payload = vec![0; len];
     assert_eq!(
-        Err(LdtError::InvalidLength(payload_len)),
-        ldt_op(ldt, &mut payload)
+        Err(LdtError::InvalidLength(len)),
+        ldt_dec.decrypt(&mut payload, &DefaultPadder::default())
+    );
+}
+
+fn do_length_check_enc(len: usize) {
+    let ldt_enc = LdtEncryptCipher::<{ BLOCK_SIZE }, XtsAes128<RustCrypto>, Swap>::new(
+        &LdtKey::<XtsAes128Key>::from_concatenated(&[0u8; 64]),
+    );
+
+    let mut payload = vec![0; len];
+    assert_eq!(
+        Err(LdtError::InvalidLength(len)),
+        ldt_enc.encrypt(&mut payload, &DefaultPadder::default())
     );
 }
diff --git a/nearby/presence/ldt_np_adv/Cargo.toml b/nearby/presence/ldt_np_adv/Cargo.toml
index b5a0471..707bb8d 100644
--- a/nearby/presence/ldt_np_adv/Cargo.toml
+++ b/nearby/presence/ldt_np_adv/Cargo.toml
@@ -13,12 +13,21 @@
 ldt_tbc.workspace = true
 
 [dev-dependencies]
-crypto_provider_rustcrypto.workspace = true
+crypto_provider_rustcrypto = {workspace = true, features=["std"]}
+crypto_provider_openssl.workspace = true
 rand_ext.workspace = true
 test_helper.workspace = true
 
 rand.workspace = true
 base64.workspace = true
-serde_json.workspace = true
+serde_json = {workspace = true, features=["std"]}
 hex.workspace = true
 anyhow.workspace = true
+criterion.workspace = true
+rand_pcg.workspace = true
+
+[[bench]]
+name = "ldt_adv_scan"
+harness = false
+
+
diff --git a/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs b/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs
new file mode 100644
index 0000000..c40530b
--- /dev/null
+++ b/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs
@@ -0,0 +1,124 @@
+// Copyright 2022 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 criterion::{black_box, criterion_group, criterion_main, Criterion};
+use ldt_np_adv::*;
+
+use array_view::ArrayView;
+use rand::{Rng as _, SeedableRng as _};
+
+use crypto_provider::CryptoProvider;
+use crypto_provider_openssl::Openssl;
+use crypto_provider_rustcrypto::RustCrypto;
+use np_hkdf::NpKeySeedHkdf;
+
+fn ldt_adv_scan<C: CryptoProvider>(c: &mut Criterion) {
+    let mut seed: <rand_pcg::Pcg64 as rand::SeedableRng>::Seed = Default::default();
+    rand::thread_rng().fill(&mut seed);
+    let mut rng = rand_pcg::Pcg64::from_seed(seed);
+
+    for &len in &[1_usize, 10, 1000] {
+        c.bench_function(&format!("Scan adv with fresh ciphers/{len}"), |b| {
+            let configs = random_configs::<C, _>(&mut rng, len);
+            let payload_len = rng.gen_range(crypto_provider::aes::BLOCK_SIZE..=LDT_XTS_AES_MAX_LEN);
+            let payload = random_vec(&mut rng, payload_len);
+
+            let salt = LegacySalt::from(rng.gen::<[u8; 2]>());
+            #[allow(clippy::unit_arg)]
+            b.iter(|| {
+                let ciphers = build_ciphers(&configs);
+                black_box(find_matching_item::<C>(&ciphers, salt, &payload))
+            });
+        });
+        c.bench_function(&format!("Scan adv with existing ciphers/{len}"), |b| {
+            let configs = random_configs::<C, _>(&mut rng, len);
+            let payload_len = rng.gen_range(crypto_provider::aes::BLOCK_SIZE..=LDT_XTS_AES_MAX_LEN);
+            let payload = random_vec(&mut rng, payload_len);
+
+            let salt = LegacySalt::from(rng.gen::<[u8; 2]>());
+            let ciphers = build_ciphers(&configs);
+            #[allow(clippy::unit_arg)]
+            b.iter(|| black_box(find_matching_item::<C>(&ciphers, salt, &payload)));
+        });
+    }
+}
+
+criterion_group!(benches, ldt_adv_scan::<RustCrypto>, ldt_adv_scan::<Openssl>);
+criterion_main!(benches);
+
+fn find_matching_item<C: CryptoProvider>(
+    ciphers: &[LdtNpAdvDecrypterXtsAes128<C>],
+    salt: LegacySalt,
+    payload: &[u8],
+) {
+    let padder = salt_padder::<16, C>(salt);
+    ciphers
+        .iter()
+        .enumerate()
+        .filter_map(|(index, item)| {
+            item.decrypt_and_verify(payload, &padder)
+                .map(|buffer| (index, buffer))
+                // any error = move to the next item
+                .ok()
+        })
+        .next()
+        .map(|(index, buffer)| MatchResult {
+            matching_index: index,
+            buffer,
+        });
+}
+
+fn build_ciphers<C: CryptoProvider>(
+    configs: &[CipherConfig<C>],
+) -> Vec<LdtNpAdvDecrypterXtsAes128<C>> {
+    configs
+        .iter()
+        .map(|config| {
+            build_np_adv_decrypter_from_key_seed(&config.key_seed, config.metadata_key_hmac)
+        })
+        .collect::<Vec<_>>()
+}
+
+struct CipherConfig<C: CryptoProvider> {
+    key_seed: NpKeySeedHkdf<C>,
+    metadata_key_hmac: [u8; 32],
+}
+
+/// `O` is the buffer size of the LDT config that produced this
+#[derive(PartialEq, Eq, Debug)]
+pub struct MatchResult<const O: usize> {
+    /// The index of the batch item that matched
+    matching_index: usize,
+    /// The buffer holding the plaintext
+    buffer: ArrayView<u8, O>,
+}
+
+fn random_configs<C: CryptoProvider, R: rand::Rng>(
+    rng: &mut R,
+    len: usize,
+) -> Vec<CipherConfig<C>> {
+    (0..len)
+        // ok to use random hmac since we want to try all configs always
+        .map(|_| CipherConfig {
+            key_seed: NpKeySeedHkdf::new(&rng.gen()),
+            metadata_key_hmac: rng.gen(),
+        })
+        .collect()
+}
+
+fn random_vec<R: rand::Rng>(rng: &mut R, len: usize) -> Vec<u8> {
+    let mut bytes = Vec::<u8>::new();
+    bytes.extend((0..len).map(|_| rng.gen::<u8>()));
+    bytes
+}
diff --git a/nearby/presence/ldt_np_adv/fuzz/Cargo.lock b/nearby/presence/ldt_np_adv/fuzz/Cargo.lock
index 6bf3469..e02e7cc 100644
--- a/nearby/presence/ldt_np_adv/fuzz/Cargo.lock
+++ b/nearby/presence/ldt_np_adv/fuzz/Cargo.lock
@@ -64,15 +64,6 @@
 
 [[package]]
 name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "block-buffer"
 version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
@@ -90,12 +81,6 @@
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
 name = "bytes"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -157,7 +142,7 @@
 checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
  "zeroize",
 ]
@@ -169,7 +154,7 @@
 checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "typenum",
 ]
 
@@ -197,10 +182,9 @@
  "p256",
  "rand",
  "rand_chacha",
- "rand_core 0.6.4",
- "rand_core_05_adapter",
+ "rand_core",
  "sec1",
- "sha2 0.10.6",
+ "sha2",
  "subtle",
  "x25519-dalek",
 ]
@@ -216,15 +200,16 @@
 
 [[package]]
 name = "curve25519-dalek"
-version = "3.2.0"
+version = "4.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
+checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585"
 dependencies = [
- "byteorder",
- "digest 0.9.0",
- "rand_core 0.5.1",
+ "cfg-if",
+ "digest",
+ "fiat-crypto",
+ "packed_simd_2",
+ "platforms",
  "subtle",
- "zeroize",
 ]
 
 [[package]]
@@ -250,43 +235,34 @@
 
 [[package]]
 name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "digest"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
- "block-buffer 0.10.4",
+ "block-buffer",
  "crypto-common",
  "subtle",
 ]
 
 [[package]]
 name = "ed25519"
-version = "1.5.3"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
 dependencies = [
  "signature",
 ]
 
 [[package]]
 name = "ed25519-dalek"
-version = "1.0.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a"
 dependencies = [
  "curve25519-dalek",
  "ed25519",
- "sha2 0.9.9",
- "zeroize",
+ "rand_core",
+ "sha2",
 ]
 
 [[package]]
@@ -297,12 +273,12 @@
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "digest 0.10.6",
+ "digest",
  "ff",
  "generic-array",
  "group",
  "hkdf",
- "rand_core 0.6.4",
+ "rand_core",
  "sec1",
  "subtle",
  "zeroize",
@@ -314,11 +290,17 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
 dependencies = [
- "rand_core 0.6.4",
+ "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.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -347,7 +329,7 @@
 checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
 dependencies = [
  "ff",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
 ]
 
@@ -366,7 +348,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
@@ -402,9 +384,11 @@
 dependencies = [
  "arbitrary",
  "crypto_provider_rustcrypto",
+ "ldt",
  "ldt_np_adv",
  "libfuzzer-sys",
  "np_hkdf",
+ "xts_aes",
 ]
 
 [[package]]
@@ -444,6 +428,12 @@
 ]
 
 [[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
+[[package]]
 name = "np_hkdf"
 version = "0.1.0"
 dependencies = [
@@ -475,6 +465,22 @@
 ]
 
 [[package]]
+name = "packed_simd_2"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
+dependencies = [
+ "cfg-if",
+ "libm",
+]
+
+[[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.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -525,7 +531,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
@@ -535,17 +541,11 @@
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-
-[[package]]
-name = "rand_core"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
@@ -554,14 +554,6 @@
 ]
 
 [[package]]
-name = "rand_core_05_adapter"
-version = "0.1.0"
-dependencies = [
- "rand",
- "rand_core 0.5.1",
-]
-
-[[package]]
 name = "sec1"
 version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -576,33 +568,20 @@
 
 [[package]]
 name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
-
-[[package]]
-name = "sha2"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
 name = "signature"
-version = "1.6.4"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
 
 [[package]]
 name = "subtle"
@@ -622,18 +601,6 @@
 ]
 
 [[package]]
-name = "synstructure"
-version = "0.12.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "unicode-xid",
-]
-
-[[package]]
 name = "typenum"
 version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -646,12 +613,6 @@
 checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
 
 [[package]]
-name = "unicode-xid"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
-
-[[package]]
 name = "universal-hash"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -675,13 +636,12 @@
 
 [[package]]
 name = "x25519-dalek"
-version = "2.0.0-pre.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df"
+checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95"
 dependencies = [
  "curve25519-dalek",
- "rand_core 0.6.4",
- "zeroize",
+ "rand_core",
 ]
 
 [[package]]
@@ -698,18 +658,3 @@
 version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
diff --git a/nearby/presence/ldt_np_adv/fuzz/Cargo.toml b/nearby/presence/ldt_np_adv/fuzz/Cargo.toml
index f74cee6..a346c6b 100644
--- a/nearby/presence/ldt_np_adv/fuzz/Cargo.toml
+++ b/nearby/presence/ldt_np_adv/fuzz/Cargo.toml
@@ -18,6 +18,10 @@
 
 [dependencies.np_hkdf]
 path = "../../np_hkdf"
+[dependencies.xts_aes]
+path = "../../xts_aes"
+[dependencies.ldt]
+path = "../../ldt"
 
 # Prevent this from interfering with workspaces
 [workspace]
diff --git a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_decrypt.rs b/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_decrypt.rs
index b8edc18..2039219 100644
--- a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_decrypt.rs
+++ b/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_decrypt.rs
@@ -21,8 +21,8 @@
     // try to decrypt data that won't pass validation
     let salt = data.salt.into();
     let padder = salt_padder::<16, RustCrypto>(salt);
-    let cipher_config = LdtAdvCipherConfig::new(data.key_seed, data.metadata_key_hmac);
-    let cipher = cipher_config.build_adv_decrypter_xts_aes_128::<RustCrypto>();
+    let hkdf = np_hkdf::NpKeySeedHkdf::<RustCrypto>::new(&data.key_seed);
+    let cipher = build_np_adv_decrypter_from_key_seed::<RustCrypto>(&hkdf, data.metadata_key_hmac);
 
     let len = 16 + (data.len as usize % 16);
     let ciphertext = data.ciphertext;
diff --git a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_roundtrip.rs b/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_roundtrip.rs
index e2b3713..69f82c3 100644
--- a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_roundtrip.rs
+++ b/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_roundtrip.rs
@@ -14,26 +14,27 @@
 // limitations under the License.
 
 use crypto_provider_rustcrypto::RustCrypto;
+use ldt::*;
 use ldt_np_adv::*;
 use libfuzzer_sys::fuzz_target;
+use xts_aes::XtsAes128;
 
 fuzz_target!(|data: LdtNpRoundtripFuzzInput| {
     let salt = data.salt.into();
     let padder = salt_padder::<16, RustCrypto>(salt);
 
     let hkdf = np_hkdf::NpKeySeedHkdf::<RustCrypto>::new(&data.key_seed);
-    let ldt = ldt_xts_aes_128::<RustCrypto>(&hkdf.legacy_ldt_key());
+    let ldt_enc = LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&hkdf.legacy_ldt_key());
     let metadata_key_hmac: [u8; 32] = hkdf
         .legacy_metadata_key_hmac_key()
         .calculate_hmac(&data.plaintext[..14]);
 
-    let cipher_config = LdtAdvCipherConfig::new(data.key_seed, metadata_key_hmac);
-    let cipher = cipher_config.build_adv_decrypter_xts_aes_128::<RustCrypto>();
+    let cipher = build_np_adv_decrypter_from_key_seed::<RustCrypto>(&hkdf, metadata_key_hmac);
 
     let len = 16 + (data.len as usize % 16);
     let mut ciphertext = data.plaintext;
 
-    ldt.encrypt(&mut ciphertext[..len], &padder).unwrap();
+    ldt_enc.encrypt(&mut ciphertext[..len], &padder).unwrap();
     let plaintext = cipher
         .decrypt_and_verify(&ciphertext[..len], &padder)
         .unwrap();
diff --git a/nearby/presence/ldt_np_adv/src/lib.rs b/nearby/presence/ldt_np_adv/src/lib.rs
index 7ab88fb..6e23573 100644
--- a/nearby/presence/ldt_np_adv/src/lib.rs
+++ b/nearby/presence/ldt_np_adv/src/lib.rs
@@ -30,12 +30,13 @@
 
 use array_view::ArrayView;
 use core::fmt;
+use crypto_provider::aes::BLOCK_SIZE;
 use crypto_provider::hmac::Hmac;
 use crypto_provider::CryptoProvider;
-use ldt::{Ldt, LdtError, LdtKey, Mix, Padder, Swap, XorPadder};
+use ldt::{LdtDecryptCipher, LdtEncryptCipher, LdtError, Mix, Padder, Swap, XorPadder};
 use ldt_tbc::TweakableBlockCipher;
-use np_hkdf::legacy_ldt_expanded_salt;
-use xts_aes::{XtsAes128, XtsAes128Key, XtsAes256, XtsAes256Key};
+use np_hkdf::{legacy_ldt_expanded_salt, NpHmacSha256Key, NpKeySeedHkdf};
+use xts_aes::XtsAes128;
 
 /// Max LDT-XTS-AES data size: `(2 * AES block size) - 1`
 pub const LDT_XTS_AES_MAX_LEN: usize = 31;
@@ -62,65 +63,63 @@
     }
 }
 
-/// Config for one individual cipher, corresponding to a particular NP identity/credential
-pub struct LdtAdvCipherConfig {
-    /// The key seed in the NP credential from which other keys will be derived
-    key_seed: [u8; 32],
-    /// The metadata key HMAC in the NP credential
-    metadata_key_hmac: [u8; 32],
+/// [LdtEncryptCipher] parameterized for XTS-AES-128 with the [Swap] mix function.
+pub type LdtEncrypterXtsAes128<C> = LdtEncryptCipher<{ BLOCK_SIZE }, XtsAes128<C>, Swap>;
+
+/// A Nearby Presence specific LDT decrypter which verifies the hmac tag of the given payload
+/// parameterized for XTS-AES-128 with the [Swap] mix function.
+pub type LdtNpAdvDecrypterXtsAes128<C> =
+    LdtNpAdvDecrypter<{ BLOCK_SIZE }, LDT_XTS_AES_MAX_LEN, XtsAes128<C>, Swap, C>;
+
+/// Build a Nearby Presence specific LDT XTS-AES-128 decrypter from a provided [NpKeySeedHkdf] and
+/// metadata_key_hmac, with the [Swap] mix function
+pub fn build_np_adv_decrypter_from_key_seed<C: CryptoProvider>(
+    key_seed: &NpKeySeedHkdf<C>,
+    metadata_key_tag: [u8; 32],
+) -> LdtNpAdvDecrypterXtsAes128<C> {
+    build_np_adv_decrypter(
+        &key_seed.legacy_ldt_key(),
+        metadata_key_tag,
+        key_seed.legacy_metadata_key_hmac_key(),
+    )
 }
 
-impl LdtAdvCipherConfig {
-    /// Build a config from the provided key seed and metadata key hmac.
-    pub fn new(key_seed: [u8; 32], metadata_key_mac: [u8; 32]) -> Self {
-        Self {
-            key_seed,
-            metadata_key_hmac: metadata_key_mac,
-        }
-    }
-
-    /// Build an LdtAdvCipher using XTS-AES128 and keys derived from the key seed.
-    pub fn build_adv_decrypter_xts_aes_128<C: CryptoProvider>(&self) -> LdtAdvDecrypterAes128<C> {
-        let hkdf = np_hkdf::NpKeySeedHkdf::new(&self.key_seed);
-
-        LdtAdvDecrypter {
-            ldt: ldt_xts_aes_128::<C>(&hkdf.legacy_ldt_key()),
-            metadata_key_hmac: self.metadata_key_hmac,
-            metadata_key_hmac_key: hkdf.legacy_metadata_key_hmac_key(),
-        }
+/// Build a Nearby Presence specific LDT XTS-AES-128 decrypter from precalculated cipher components,
+/// with the [Swap] mix function
+pub fn build_np_adv_decrypter<C: CryptoProvider>(
+    ldt_key: &ldt::LdtKey<xts_aes::XtsAes128Key>,
+    metadata_key_tag: [u8; 32],
+    metadata_key_hmac_key: NpHmacSha256Key<C>,
+) -> LdtNpAdvDecrypterXtsAes128<C> {
+    LdtNpAdvDecrypter {
+        ldt_decrypter: LdtXtsAes128Decrypter::<C>::new(ldt_key),
+        metadata_key_tag,
+        metadata_key_hmac_key,
     }
 }
 
+// [LdtDecryptCipher] parameterized for XTS-AES-128 with the [Swap] mix function.
+type LdtXtsAes128Decrypter<C> = LdtDecryptCipher<{ BLOCK_SIZE }, XtsAes128<C>, Swap>;
+
 /// Decrypts and validates a NP legacy format advertisement encrypted with LDT.
 ///
-/// Use an [LdtAdvCipherConfig] to build one from an NP `key_seed`.
-///
 /// `B` is the underlying block cipher block size.
 /// `O` is the max output size (must be 2 * B - 1).
 /// `T` is the tweakable block cipher used by LDT.
 /// `M` is the mix function used by LDT.
-pub struct LdtAdvDecrypter<
+pub struct LdtNpAdvDecrypter<
     const B: usize,
     const O: usize,
     T: TweakableBlockCipher<B>,
     M: Mix,
     C: CryptoProvider,
 > {
-    ldt: Ldt<B, T, M>,
-    metadata_key_hmac: [u8; 32],
+    ldt_decrypter: LdtDecryptCipher<B, T, M>,
+    metadata_key_tag: [u8; 32],
     metadata_key_hmac_key: np_hkdf::NpHmacSha256Key<C>,
 }
 
-/// An LdtAdvCipher with block size set appropriately for AES.
-pub type LdtAdvDecrypterAes128<C> = LdtAdvDecrypter<
-    { crypto_provider::aes::BLOCK_SIZE },
-    LDT_XTS_AES_MAX_LEN,
-    xts_aes::XtsAes128<C>,
-    Swap,
-    C,
->;
-
-impl<const B: usize, const O: usize, T, M, C> LdtAdvDecrypter<B, O, T, M, C>
+impl<const B: usize, const O: usize, T, M, C> LdtNpAdvDecrypter<B, O, T, M, C>
 where
     T: TweakableBlockCipher<B>,
     M: Mix,
@@ -150,7 +149,7 @@
         buffer[..payload.len()].copy_from_slice(payload);
 
         #[allow(clippy::expect_used)]
-        self.ldt
+        self.ldt_decrypter
             .decrypt(&mut buffer[..payload.len()], padder)
             .map_err(|e| match e {
                 LdtError::InvalidLength(l) => LdtAdvDecryptError::InvalidLength(l),
@@ -158,7 +157,7 @@
             .and_then(|_| {
                 let mut hmac = self.metadata_key_hmac_key.build_hmac();
                 hmac.update(&buffer[..NP_LEGACY_METADATA_KEY_LEN]);
-                hmac.verify_slice(&self.metadata_key_hmac)
+                hmac.verify_slice(&self.metadata_key_tag)
                     .map_err(|_| LdtAdvDecryptError::MacMismatch)
                     .map(|_| {
                         ArrayView::try_from_array(buffer, payload.len())
@@ -166,39 +165,9 @@
                     })
             })
     }
-
-    /// Encrypt the payload in place using the provided padder.
-    ///
-    /// No validation is done to ensure that the metadata key is correct.
-    ///
-    /// # Errors
-    /// - If `payload` has a length outside of `[B, B * 2)`.
-    // Leaving it in place, but deprecating it, to avoid breaking ldt_np_adv_ffi which will be
-    // replaced by a much more expansive FFI API soon.
-    #[deprecated]
-    pub fn encrypt<P: Padder<B, T>>(&self, payload: &mut [u8], padder: &P) -> Result<(), LdtError> {
-        assert_eq!(B * 2 - 1, O); // should be compiled away
-
-        self.ldt.encrypt(payload, padder)
-    }
-
-    /// Construct a cipher from its component parts.
-    ///
-    /// See also [LdtAdvCipherConfig] to build a cipher from an NP key seed.
-    pub fn new(
-        ldt: Ldt<B, T, M>,
-        metadata_key_hmac: [u8; 32],
-        metadata_key_hmac_key: np_hkdf::NpHmacSha256Key<C>,
-    ) -> Self {
-        Self {
-            ldt,
-            metadata_key_hmac,
-            metadata_key_hmac_key,
-        }
-    }
 }
 
-/// Errors that can occur during [LdtAdvCipher.decrypt_and_verify].
+/// Errors that can occur during [LdtNpAdvDecrypter::decrypt_and_verify].
 #[derive(Debug, PartialEq, Eq)]
 pub enum LdtAdvDecryptError {
     /// The ciphertext data was an invalid length.
@@ -223,19 +192,3 @@
     // If that's ever not true, yet another generic parameter will address that.
     XorPadder::from(legacy_ldt_expanded_salt::<B, C>(&salt.bytes))
 }
-
-/// [Ldt] parameterized for XTS-AES-128 with the [Swap] mix function.
-pub type LdtXtsAes128<C> = Ldt<{ crypto_provider::aes::BLOCK_SIZE }, XtsAes128<C>, Swap>;
-
-/// Build an [Ldt] with [xts_aes::Xts]-AES-128 and the [Swap] mix function.
-pub fn ldt_xts_aes_128<C: CryptoProvider>(key: &LdtKey<XtsAes128Key>) -> LdtXtsAes128<C> {
-    Ldt::new(key)
-}
-
-/// [Ldt] parameterized for XTS-AES-256 with the [Swap] mix function.
-pub type LdtXtsAes256<C> = Ldt<{ crypto_provider::aes::BLOCK_SIZE }, XtsAes256<C>, Swap>;
-
-/// Build an [Ldt] with [xts_aes::Xts]-AES-256 and the [Swap] mix function.
-pub fn ldt_xts_aes_256<C: CryptoProvider>(key: &LdtKey<XtsAes256Key>) -> LdtXtsAes256<C> {
-    Ldt::new(key)
-}
diff --git a/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs b/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs
index 14a96d6..46c9968 100644
--- a/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs
+++ b/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs
@@ -21,7 +21,8 @@
 extern crate std;
 
 use crate::{
-    ldt_xts_aes_128, salt_padder, LdtAdvCipherConfig, LegacySalt, NP_LEGACY_METADATA_KEY_LEN,
+    build_np_adv_decrypter_from_key_seed, salt_padder, LdtEncrypterXtsAes128, LegacySalt,
+    NP_LEGACY_METADATA_KEY_LEN,
 };
 use anyhow::anyhow;
 use crypto_provider_rustcrypto::RustCrypto;
@@ -59,16 +60,18 @@
         let salt = LegacySalt::from(extract_key_array(&tc, "adv_salt"));
         let padder = salt_padder::<16, RustCrypto>(salt);
 
-        let ldt = ldt_xts_aes_128::<RustCrypto>(&ldt_key);
+        let ldt_enc = LdtEncrypterXtsAes128::<RustCrypto>::new(&ldt_key);
 
-        let config = LdtAdvCipherConfig::new(key_seed, extract_key_array(&tc, "metadata_key_hmac"));
-        let decrypter = config.build_adv_decrypter_xts_aes_128::<RustCrypto>();
+        let decrypter = build_np_adv_decrypter_from_key_seed(
+            &hkdf,
+            extract_key_array(&tc, "metadata_key_hmac"),
+        );
 
         let plaintext = extract_key_vec(&tc, "plaintext");
         let ciphertext = extract_key_vec(&tc, "ciphertext");
 
         let mut ciphertext_actual = plaintext.clone();
-        ldt.encrypt(&mut ciphertext_actual, &padder).unwrap();
+        ldt_enc.encrypt(&mut ciphertext_actual, &padder).unwrap();
 
         assert_eq!(ciphertext, ciphertext_actual);
 
@@ -98,11 +101,11 @@
         let ldt_key = hkdf.legacy_ldt_key();
         let hmac_key = hkdf.legacy_metadata_key_hmac_key();
         let hmac: [u8; 32] = hmac_key.calculate_hmac(&plaintext[..NP_LEGACY_METADATA_KEY_LEN]);
-        let ldt = ldt_xts_aes_128::<RustCrypto>(&ldt_key);
+        let ldt_enc = LdtEncrypterXtsAes128::<RustCrypto>::new(&ldt_key);
 
         let padder = salt_padder::<16, RustCrypto>(LegacySalt::from(rng.gen::<[u8; 2]>()));
         let mut ciphertext = plaintext.clone();
-        ldt.encrypt(&mut ciphertext[..], &padder).unwrap();
+        ldt_enc.encrypt(&mut ciphertext[..], &padder).unwrap();
 
         array.push(json!({
             "key_seed": hex::encode_upper(key_seed),
diff --git a/nearby/presence/ldt_np_adv/src/tests.rs b/nearby/presence/ldt_np_adv/src/tests.rs
index d1be881..5f09e33 100644
--- a/nearby/presence/ldt_np_adv/src/tests.rs
+++ b/nearby/presence/ldt_np_adv/src/tests.rs
@@ -21,13 +21,15 @@
 extern crate alloc;
 
 use crate::{
-    ldt_xts_aes_128, salt_padder, LdtAdvDecryptError, LdtAdvDecrypterAes128, LdtXtsAes128,
-    LegacySalt, LDT_XTS_AES_MAX_LEN, NP_LEGACY_METADATA_KEY_LEN,
+    build_np_adv_decrypter_from_key_seed, salt_padder, LdtAdvDecryptError, LdtEncrypterXtsAes128,
+    LdtNpAdvDecrypterXtsAes128, LdtXtsAes128Decrypter, LegacySalt, LDT_XTS_AES_MAX_LEN,
+    NP_LEGACY_METADATA_KEY_LEN,
 };
 use alloc::vec::Vec;
 use crypto_provider::CryptoProvider;
 use crypto_provider_rustcrypto::RustCrypto;
 use ldt::{DefaultPadder, LdtError, LdtKey, XorPadder};
+use np_hkdf::NpKeySeedHkdf;
 use rand_ext::{random_vec, seeded_rng};
 
 #[test]
@@ -36,11 +38,7 @@
     for _ in 0..1_000 {
         let test_state = make_test_components::<_, RustCrypto>(&mut rng);
 
-        let cipher = LdtAdvDecrypterAes128 {
-            ldt: test_state.ldt,
-            metadata_key_hmac: test_state.hmac,
-            metadata_key_hmac_key: test_state.hmac_key,
-        };
+        let cipher = build_np_adv_decrypter_from_key_seed(&test_state.hkdf, test_state.hmac);
         let decrypted = cipher
             .decrypt_and_verify(&test_state.ciphertext, &test_state.padder)
             .unwrap();
@@ -58,11 +56,7 @@
         // mangle the ciphertext
         test_state.ciphertext[0] ^= 0xAA;
 
-        let cipher = LdtAdvDecrypterAes128 {
-            ldt: test_state.ldt,
-            metadata_key_hmac: test_state.hmac,
-            metadata_key_hmac_key: test_state.hmac_key,
-        };
+        let cipher = build_np_adv_decrypter_from_key_seed(&test_state.hkdf, test_state.hmac);
         assert_eq!(
             Err(LdtAdvDecryptError::MacMismatch),
             cipher.decrypt_and_verify(&test_state.ciphertext, &test_state.padder)
@@ -79,12 +73,7 @@
         // mangle the mac
         test_state.hmac[0] ^= 0xAA;
 
-        let cipher = LdtAdvDecrypterAes128 {
-            ldt: test_state.ldt,
-            metadata_key_hmac: test_state.hmac,
-            metadata_key_hmac_key: test_state.hmac_key,
-        };
-
+        let cipher = build_np_adv_decrypter_from_key_seed(&test_state.hkdf, test_state.hmac);
         assert_eq!(
             Err(LdtAdvDecryptError::MacMismatch),
             cipher.decrypt_and_verify(&test_state.ciphertext, &test_state.padder)
@@ -99,11 +88,7 @@
     for _ in 0..1_000 {
         let test_state = make_test_components::<_, RustCrypto>(&mut rng);
 
-        let cipher = LdtAdvDecrypterAes128 {
-            ldt: test_state.ldt,
-            metadata_key_hmac: test_state.hmac,
-            metadata_key_hmac_key: test_state.hmac_key,
-        };
+        let cipher = test_state.ldt_enc;
 
         let mut plaintext_copy = test_state.plaintext.clone();
         cipher
@@ -117,43 +102,34 @@
 #[test]
 #[allow(deprecated)]
 fn encrypt_too_short_err() {
-    let ldt = ldt_xts_aes_128::<RustCrypto>(&LdtKey::from_concatenated(&[0; 64]));
-    let adv_cipher = LdtAdvDecrypterAes128 {
-        ldt,
-        metadata_key_hmac: [0; 32],
-        metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::<RustCrypto>::from([0; 32]),
-    };
+    let ldt_enc = LdtEncrypterXtsAes128::<RustCrypto>::new(&LdtKey::from_concatenated(&[0; 64]));
 
     let mut payload = [0; 7];
     assert_eq!(
         Err(LdtError::InvalidLength(7)),
-        adv_cipher.encrypt(&mut payload, &DefaultPadder::default())
+        ldt_enc.encrypt(&mut payload, &DefaultPadder::default())
     );
 }
 
 #[test]
 #[allow(deprecated)]
 fn encrypt_too_long_err() {
-    let ldt = ldt_xts_aes_128::<RustCrypto>(&LdtKey::from_concatenated(&[0; 64]));
-    let adv_cipher = LdtAdvDecrypterAes128 {
-        ldt,
-        metadata_key_hmac: [0; 32],
-        metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::<RustCrypto>::from([0; 32]),
-    };
+    let ldt_enc = LdtEncrypterXtsAes128::<RustCrypto>::new(&LdtKey::from_concatenated(&[0; 64]));
 
     let mut payload = [0; 40];
     assert_eq!(
         Err(LdtError::InvalidLength(40)),
-        adv_cipher.encrypt(&mut payload, &DefaultPadder::default())
+        ldt_enc.encrypt(&mut payload, &DefaultPadder::default())
     );
 }
 
 #[test]
 fn decrypt_too_short_err() {
-    let ldt = ldt_xts_aes_128::<RustCrypto>(&LdtKey::from_concatenated(&[0; 64]));
-    let adv_cipher = LdtAdvDecrypterAes128 {
-        ldt,
-        metadata_key_hmac: [0; 32],
+    let adv_cipher = LdtNpAdvDecrypterXtsAes128 {
+        ldt_decrypter: LdtXtsAes128Decrypter::<RustCrypto>::new(&LdtKey::from_concatenated(
+            &[0; 64],
+        )),
+        metadata_key_tag: [0; 32],
         metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::<RustCrypto>::from([0; 32]),
     };
 
@@ -166,10 +142,11 @@
 
 #[test]
 fn decrypt_too_long_err() {
-    let ldt = ldt_xts_aes_128::<RustCrypto>(&LdtKey::from_concatenated(&[0; 64]));
-    let adv_cipher = LdtAdvDecrypterAes128 {
-        ldt,
-        metadata_key_hmac: [0; 32],
+    let adv_cipher = LdtNpAdvDecrypterXtsAes128 {
+        ldt_decrypter: LdtXtsAes128Decrypter::<RustCrypto>::new(&LdtKey::from_concatenated(
+            &[0; 64],
+        )),
+        metadata_key_tag: [0; 32],
         metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::<RustCrypto>::from([0; 32]),
     };
 
@@ -198,20 +175,21 @@
     let hmac_key = hkdf.legacy_metadata_key_hmac_key();
     let hmac: [u8; 32] = hmac_key.calculate_hmac(&plaintext[..NP_LEGACY_METADATA_KEY_LEN]);
 
-    let ldt = ldt_xts_aes_128::<C>(&ldt_key);
+    let ldt_enc = LdtEncrypterXtsAes128::<C>::new(&ldt_key);
 
     let mut ciphertext = [0_u8; LDT_XTS_AES_MAX_LEN];
     ciphertext[..plaintext.len()].copy_from_slice(&plaintext);
-    ldt.encrypt(&mut ciphertext[..plaintext.len()], &padder)
+    ldt_enc
+        .encrypt(&mut ciphertext[..plaintext.len()], &padder)
         .unwrap();
 
     LdtAdvTestComponents {
         plaintext,
         ciphertext: ciphertext[..payload_len].to_vec(),
         padder,
-        hmac_key,
         hmac,
-        ldt,
+        ldt_enc,
+        hkdf,
     }
 }
 
@@ -219,7 +197,7 @@
     plaintext: Vec<u8>,
     ciphertext: Vec<u8>,
     padder: XorPadder<{ crypto_provider::aes::BLOCK_SIZE }>,
-    hmac_key: np_hkdf::NpHmacSha256Key<C>,
     hmac: [u8; 32],
-    ldt: LdtXtsAes128<C>,
+    ldt_enc: LdtEncrypterXtsAes128<C>,
+    hkdf: NpKeySeedHkdf<C>,
 }
diff --git a/nearby/presence/ldt_np_adv_ffi/Cargo.lock b/nearby/presence/ldt_np_adv_ffi/Cargo.lock
index 3c91225..5deadcc 100644
--- a/nearby/presence/ldt_np_adv_ffi/Cargo.lock
+++ b/nearby/presence/ldt_np_adv_ffi/Cargo.lock
@@ -10,9 +10,9 @@
 
 [[package]]
 name = "aead"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
 dependencies = [
  "bytes",
  "crypto-common",
@@ -67,9 +67,15 @@
 
 [[package]]
 name = "base16ct"
-version = "0.1.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
 
 [[package]]
 name = "bitflags"
@@ -79,15 +85,6 @@
 
 [[package]]
 name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "block-buffer"
 version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
@@ -97,18 +94,23 @@
 
 [[package]]
 name = "block-padding"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a90ec2df9600c28a01c56c4784c9207a96d2451833aeceb8cc97e4c9548bb78"
+checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
 dependencies = [
  "generic-array",
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+name = "bssl-crypto"
+version = "0.1.0"
+dependencies = [
+ "bssl-sys",
+]
+
+[[package]]
+name = "bssl-sys"
+version = "0.1.0"
 
 [[package]]
 name = "bytes"
@@ -164,12 +166,12 @@
 
 [[package]]
 name = "crypto-bigint"
-version = "0.4.9"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
+checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
  "zeroize",
 ]
@@ -181,7 +183,7 @@
 checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "typenum",
 ]
 
@@ -193,6 +195,15 @@
 ]
 
 [[package]]
+name = "crypto_provider_boringssl"
+version = "0.1.0"
+dependencies = [
+ "bssl-crypto",
+ "crypto_provider",
+ "crypto_provider_stubs",
+]
+
+[[package]]
 name = "crypto_provider_openssl"
 version = "0.1.0"
 dependencies = [
@@ -217,17 +228,23 @@
  "hkdf",
  "hmac",
  "p256",
- "rand 0.8.5",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
- "rand_core_05_adapter",
+ "rand",
+ "rand_chacha",
+ "rand_core",
  "sec1",
- "sha2 0.10.6",
+ "sha2",
  "subtle",
  "x25519-dalek",
 ]
 
 [[package]]
+name = "crypto_provider_stubs"
+version = "0.1.0"
+dependencies = [
+ "crypto_provider",
+]
+
+[[package]]
 name = "ctr"
 version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -238,33 +255,27 @@
 
 [[package]]
 name = "curve25519-dalek"
-version = "3.2.0"
+version = "4.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
+checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585"
 dependencies = [
- "byteorder",
- "digest 0.9.0",
- "rand_core 0.5.1",
+ "cfg-if",
+ "digest",
+ "fiat-crypto",
+ "packed_simd_2",
+ "platforms",
  "subtle",
  "zeroize",
 ]
 
 [[package]]
 name = "der"
-version = "0.6.1"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
+checksum = "bc906908ea6458456e5eaa160a9c08543ec3d1e6f71e2235cedd660cb65f9df0"
 dependencies = [
  "const-oid",
-]
-
-[[package]]
-name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
+ "zeroize",
 ]
 
 [[package]]
@@ -273,49 +284,49 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
- "block-buffer 0.10.4",
+ "block-buffer",
  "crypto-common",
  "subtle",
 ]
 
 [[package]]
 name = "ed25519"
-version = "1.5.3"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
 dependencies = [
+ "pkcs8",
  "signature",
 ]
 
 [[package]]
 name = "ed25519-dalek"
-version = "1.0.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a"
 dependencies = [
  "curve25519-dalek",
  "ed25519",
- "rand 0.7.3",
+ "rand_core",
  "serde",
- "sha2 0.9.9",
+ "sha2",
  "zeroize",
 ]
 
 [[package]]
 name = "elliptic-curve"
-version = "0.12.3"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
+checksum = "6ea5a92946e8614bb585254898bb7dd1ddad241ace60c52149e3765e34cc039d"
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "der",
- "digest 0.10.6",
+ "digest",
  "ff",
  "generic-array",
  "group",
  "hkdf",
- "rand_core 0.6.4",
+ "rand_core",
  "sec1",
  "subtle",
  "zeroize",
@@ -323,15 +334,21 @@
 
 [[package]]
 name = "ff"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
+checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
 dependencies = [
- "rand_core 0.6.4",
+ "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 = "foreign-types"
 version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -348,23 +365,13 @@
 
 [[package]]
 name = "generic-array"
-version = "0.14.6"
+version = "0.14.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
 dependencies = [
  "typenum",
  "version_check",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.9.0+wasi-snapshot-preview1",
+ "zeroize",
 ]
 
 [[package]]
@@ -375,17 +382,17 @@
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
 ]
 
 [[package]]
 name = "group"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
 dependencies = [
  "ff",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
 ]
 
@@ -404,7 +411,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
@@ -431,7 +438,7 @@
 version = "0.1.0"
 dependencies = [
  "ldt_tbc",
- "rand 0.8.5",
+ "rand",
 ]
 
 [[package]]
@@ -452,29 +459,31 @@
 dependencies = [
  "cfg-if",
  "crypto_provider",
+ "crypto_provider_boringssl",
  "crypto_provider_openssl",
  "crypto_provider_rustcrypto",
  "lazy_static",
  "ldt",
  "ldt_np_adv",
  "libc_alloc",
+ "np_hkdf",
  "panic-abort",
- "rand 0.8.5",
- "spin 0.9.7",
+ "rand",
+ "spin 0.9.8",
 ]
 
 [[package]]
 name = "ldt_tbc"
 version = "0.1.0"
 dependencies = [
- "rand 0.8.5",
+ "rand",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.140"
+version = "0.2.141"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
+checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
 
 [[package]]
 name = "libc_alloc"
@@ -483,6 +492,12 @@
 checksum = "6a090348b66d90d8507e30f0d2bd88e5a5c454bd1733fc6d617cbc3471bf69ea"
 
 [[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
+[[package]]
 name = "lock_api"
 version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -515,9 +530,9 @@
 
 [[package]]
 name = "openssl"
-version = "0.10.48"
+version = "0.10.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2"
+checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -530,22 +545,21 @@
 
 [[package]]
 name = "openssl-macros"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.13",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.83"
+version = "0.9.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b"
+checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
 dependencies = [
- "autocfg",
  "cc",
  "libc",
  "pkg-config",
@@ -577,27 +591,53 @@
 
 [[package]]
 name = "p256"
-version = "0.12.0"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49c124b3cbce43bcbac68c58ec181d98ed6cc7e6d0aa7c3ba97b2563410b0e55"
+checksum = "7270da3e5caa82afd3deb054cc237905853813aea3859544bc082c3fe55b8d47"
 dependencies = [
  "elliptic-curve",
  "primeorder",
 ]
 
 [[package]]
+name = "packed_simd_2"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
+dependencies = [
+ "cfg-if",
+ "libm",
+]
+
+[[package]]
 name = "panic-abort"
 version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4e20e6499bbbc412f280b04a42346b356c6fa0753d5fd22b7bd752ff34c778ee"
 
 [[package]]
+name = "pkcs8"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d2820d87d2b008616e5c27212dd9e0e694fb4c6b522de06094106813328cb49"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
 name = "pkg-config"
 version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
 
 [[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.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -617,9 +657,9 @@
 
 [[package]]
 name = "primeorder"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b54f7131b3dba65a2f414cf5bd25b66d4682e4608610668eae785750ba4c5b2"
+checksum = "7613fdcc0831c10060fa69833ea8fa2caa94b6456f51e25356a885b530a2e3d0"
 dependencies = [
  "elliptic-curve",
 ]
@@ -650,9 +690,9 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.54"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
 dependencies = [
  "unicode-ident",
 ]
@@ -668,36 +708,13 @@
 
 [[package]]
 name = "rand"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "getrandom 0.1.16",
- "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc",
-]
-
-[[package]]
-name = "rand"
 version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.5.1",
+ "rand_chacha",
+ "rand_core",
 ]
 
 [[package]]
@@ -707,16 +724,7 @@
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-dependencies = [
- "getrandom 0.1.16",
+ "rand_core",
 ]
 
 [[package]]
@@ -725,24 +733,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom 0.2.8",
-]
-
-[[package]]
-name = "rand_core_05_adapter"
-version = "0.1.0"
-dependencies = [
- "rand 0.8.5",
- "rand_core 0.5.1",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-dependencies = [
- "rand_core 0.5.1",
+ "getrandom",
 ]
 
 [[package]]
@@ -753,9 +744,9 @@
 
 [[package]]
 name = "sec1"
-version = "0.3.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
+checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e"
 dependencies = [
  "base16ct",
  "der",
@@ -766,22 +757,9 @@
 
 [[package]]
 name = "serde"
-version = "1.0.158"
+version = "1.0.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
-
-[[package]]
-name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
+checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
 
 [[package]]
 name = "sha2"
@@ -791,14 +769,14 @@
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
 name = "signature"
-version = "1.6.4"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
 
 [[package]]
 name = "spin"
@@ -808,14 +786,24 @@
 
 [[package]]
 name = "spin"
-version = "0.9.7"
+version = "0.9.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0959fd6f767df20b231736396e4f602171e00d95205676286e79d4a4eb67bef"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
 dependencies = [
  "lock_api",
 ]
 
 [[package]]
+name = "spki"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0445c905640145c7ea8c1993555957f65e7c46d0535b91ba501bc9bfc85522f"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
 name = "subtle"
 version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -834,9 +822,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.10"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40"
+checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -879,25 +867,18 @@
 
 [[package]]
 name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
-
-[[package]]
-name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "x25519-dalek"
-version = "2.0.0-pre.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df"
+checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95"
 dependencies = [
  "curve25519-dalek",
- "rand_core 0.6.4",
- "zeroize",
+ "rand_core",
 ]
 
 [[package]]
@@ -914,17 +895,3 @@
 version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25588073e5216b50bca71d61cb8595cdb9745e87032a58c199730def2862c934"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.10",
-]
diff --git a/nearby/presence/ldt_np_adv_ffi/Cargo.toml b/nearby/presence/ldt_np_adv_ffi/Cargo.toml
index 5a3fada..d53809f 100644
--- a/nearby/presence/ldt_np_adv_ffi/Cargo.toml
+++ b/nearby/presence/ldt_np_adv_ffi/Cargo.toml
@@ -8,8 +8,10 @@
 crypto_provider = { path = "../../crypto/crypto_provider" }
 crypto_provider_openssl = {path = "../../crypto/crypto_provider_openssl", optional = true}
 crypto_provider_rustcrypto = {path = "../../crypto/crypto_provider_rustcrypto", optional = true}
+crypto_provider_boringssl = {path = "../../crypto/crypto_provider_boringssl", optional = true}
 ldt = { path = "../ldt" }
 ldt_np_adv = { path = "../ldt_np_adv" }
+np_hkdf = {path = "../np_hkdf"}
 
 cfg-if = "1.0.0"
 lazy_static = { version = "1.4.0"}
@@ -17,19 +19,21 @@
 # no_std only deps
 libc_alloc = {version = "1.0.4", optional = true }
 panic-abort = { version = "0.3.2", optional = true }
-spin = {version = "0.9.4", optional = true }
+spin = {version = "0.9.8", optional = true }
 
 [dev-dependencies]
 rand = "0.8.5"
 
 [lib]
-crate-type = ["cdylib", "staticlib"]
+# boringssl and bssl-sys are built as a static lib, so we need to as well
+crate-type = ["staticlib"]
 
 [features]
 # by default we support no_std and use rustcrypto primitives
 default = ["lazy_static/spin_no_std", "spin", "libc_alloc", "panic-abort", "crypto_provider_rustcrypto"]
 std = ["crypto_provider_rustcrypto", "crypto_provider_rustcrypto/std"]
-openssl = ["crypto_provider_openssl", "std"]
+openssl = ["crypto_provider_openssl"]
+boringssl = ["crypto_provider_boringssl"]
 
 [profile.release-min-size]
 inherits = "release"
diff --git a/nearby/presence/ldt_np_adv_ffi/deny.toml b/nearby/presence/ldt_np_adv_ffi/deny.toml
index 5bc6eaf..07381d1 100644
--- a/nearby/presence/ldt_np_adv_ffi/deny.toml
+++ b/nearby/presence/ldt_np_adv_ffi/deny.toml
@@ -79,8 +79,6 @@
     "MIT",
     "Apache-2.0",
     "BSD-3-Clause",
-    "Unicode-DFS-2016",
-    "Unlicense"
 ]
 # List of explicitly disallowed licenses
 # See https://spdx.org/licenses/ for list of possible licenses
diff --git a/nearby/presence/ldt_np_adv_ffi/include/np_ldt.h b/nearby/presence/ldt_np_adv_ffi/include/np_ldt.h
index 02bbe7d..13af781 100644
--- a/nearby/presence/ldt_np_adv_ffi/include/np_ldt.h
+++ b/nearby/presence/ldt_np_adv_ffi/include/np_ldt.h
@@ -19,9 +19,6 @@
 //
 // [1] https://eprint.iacr.org/2017/841.pdf
 
-// TODO pluggable memory allocation for embedded
-
-// TODO include guard name based on final file location
 #ifndef NP_LDT_H_
 #define NP_LDT_H_
 
@@ -35,23 +32,34 @@
 // Individual encrypt/decrypt API, useful when creating advertisements or when
 // decrypting advertisements from a known origin
 
-// Handle for accessing the rust ldt implementation apis
-typedef uint64_t NpLdtHandle;
-
 // Key material from the Nearby Presence credential from which keys will be
 // derived.
 typedef struct {
   uint8_t bytes[32];
 } NpLdtKeySeed;
 
+// The calculated hmac key used for verifying successful decryption of
+// credential metadata
 typedef struct{
   uint8_t bytes[32];
 } NpMetadataKeyHmac;
 
+// The big-endian  2 byte salt which will be incorporated into the tweaks LDT
+// uses while encrypting.
 typedef struct {
   uint8_t bytes[2];
 } NpLdtSalt;
 
+// The allocated handle to use for encryption
+typedef struct {
+  uint64_t handle;
+} NpLdtEncryptHandle;
+
+// The allocated handle to use for decryption
+typedef struct {
+  uint64_t handle;
+} NpLdtDecryptHandle;
+
 // Possible result codes returned from the LDT NP APIs
 typedef enum {
   // Call to api was successful
@@ -64,20 +72,33 @@
   NP_LDT_INVALID_HANDLE = -3
 } NP_LDT_RESULT;
 
-// Allocate an LDT-XTS-AES128 cipher using the "swap" mix function.
+// Allocate an LDT-XTS-AES128 Decryption cipher using the "swap" mix function.
 //
-// `aes_config` defines the AES impl that will be used.
+// `key_seed` is the key material from the Nearby Presence credential from which
+// the LDT key will be derived.
+// 'hmac_tag' is the hmac auth tag calculated on the metadata key used to verify
+// decryption was successful
+//
+// Returns 0 on error, or a non-zero handle on success.
+NpLdtDecryptHandle NpLdtDecryptCreate(NpLdtKeySeed key_seed, NpMetadataKeyHmac hmac_tag);
+
+// Allocate an LDT-XTS-AES128 Encryption cipher using the "swap" mix function.
+//
 // `key_seed` is the key material from the Nearby Presence credential from which
 // the LDT key will be derived.
 //
 // Returns 0 on error, or a non-zero handle on success.
-NpLdtHandle NpLdtCreate(NpLdtKeySeed key_seed, NpMetadataKeyHmac known_hmac);
+NpLdtEncryptHandle NpLdtEncryptCreate(NpLdtKeySeed key_seed);
 
-// Release resources for an NpLdtHandle allocated by
-// `np_ldt_create_xts_aes_128`.
+// Release allocated resources for an NpLdtEncryptHandle
 //
 // Returns 0 on success or an NP_LDT_RESULT error code on failure
-NP_LDT_RESULT NpLdtClose(NpLdtHandle handle);
+NP_LDT_RESULT NpLdtEncryptClose(NpLdtEncryptHandle handle);
+
+// Release allocated resources for an NpLdtDecryptHandle
+//
+// Returns 0 on success or an NP_LDT_RESULT error code on failure
+NP_LDT_RESULT NpLdtDecryptClose(NpLdtDecryptHandle handle);
 
 // Encrypt a 16-31 byte buffer in-place.
 //
@@ -88,7 +109,7 @@
 //
 // Returns 0 on success, in which case `buffer` will now contain ciphertext.
 // Returns an NP_LDT_RESULT error code on failure
-NP_LDT_RESULT NpLdtEncrypt(NpLdtHandle handle, uint8_t* buffer, size_t buffer_len,
+NP_LDT_RESULT NpLdtEncrypt(NpLdtEncryptHandle handle, uint8_t* buffer, size_t buffer_len,
                      NpLdtSalt salt);
 
 // Decrypt a 16-31 byte buffer in-place and verify the plaintext metadata key matches
@@ -102,9 +123,9 @@
 //
 // Returns 0 on success, in which case `buffer` will now contain plaintext.
 // Returns an NP_LDT_RESULT error code on failure
-/// - If the buffer has an invalid length
-/// - If the decrypted plaintext fails its HMAC validation
-NP_LDT_RESULT NpLdtDecryptAndVerify(NpLdtHandle handle, uint8_t* buffer, size_t buffer_len,
+// - If the buffer has an invalid length
+// - If the decrypted plaintext fails its HMAC validation
+NP_LDT_RESULT NpLdtDecryptAndVerify(NpLdtDecryptHandle handle, uint8_t* buffer, size_t buffer_len,
                      NpLdtSalt salt);
 
 #ifdef __cplusplus
diff --git a/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs b/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs
index 0b3dfda..9d83c19 100644
--- a/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs
+++ b/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs
@@ -14,6 +14,7 @@
 
 use crate::Box;
 use crate::LdtAdvDecrypter;
+use crate::LdtAdvEncrypter;
 use core::marker::PhantomData;
 use crypto_provider::{CryptoProvider, CryptoRng};
 use lazy_static::lazy_static;
@@ -21,7 +22,7 @@
 // Pull in the needed deps for std vs no_std
 cfg_if::cfg_if! {
     // Test pulls in std which causes duplicate errors
-    if #[cfg(any(feature = "std", test))] {
+    if #[cfg(any(feature = "std", test, feature = "boringssl", feature = "openssl"))] {
         use std::sync::{Mutex, MutexGuard};
         use std::collections::HashMap;
 
@@ -42,10 +43,19 @@
         }
 
         // returns a thread safe instance of the global static hashmap tracking the cipher handles
-        pub (crate) fn get_handle_map() -> MutexGuard<'static, HandleMap<Box<LdtAdvDecrypter>>> {
+        pub (crate) fn get_enc_handle_map() -> MutexGuard<'static, HandleMap<Box<LdtAdvEncrypter>>> {
             // Note even in the case of an error, the lock is still acquired, it just means whichever
             // thread was holding it panicked, we will continue on as either way we acquired the lock
-            HANDLE_MAP
+            ENCRYPT_HANDLE_MAP
+                .lock()
+                .unwrap_or_else(|err_guard| err_guard.into_inner())
+        }
+
+        // returns a thread safe instance of the global static hashmap tracking the cipher handles
+        pub (crate) fn get_dec_handle_map() -> MutexGuard<'static, HandleMap<Box<LdtAdvDecrypter>>> {
+            // Note even in the case of an error, the lock is still acquired, it just means whichever
+            // thread was holding it panicked, we will continue on as either way we acquired the lock
+            DECRYPT_HANDLE_MAP
                 .lock()
                 .unwrap_or_else(|err_guard| err_guard.into_inner())
         }
@@ -69,8 +79,13 @@
         }
 
         // returns a thread safe instance of the global static hashmap tracking the cipher handles
-        pub (crate) fn get_handle_map() -> MutexGuard<'static, HandleMap<Box<LdtAdvDecrypter>>> {
-            HANDLE_MAP.lock()
+        pub (crate) fn get_enc_handle_map() -> MutexGuard<'static, HandleMap<Box<LdtAdvEncrypter>>> {
+            ENCRYPT_HANDLE_MAP.lock()
+        }
+
+        // returns a thread safe instance of the global static hashmap tracking the cipher handles
+        pub (crate) fn get_dec_handle_map() -> MutexGuard<'static, HandleMap<Box<LdtAdvDecrypter>>> {
+            DECRYPT_HANDLE_MAP.lock()
         }
     }
 }
@@ -78,7 +93,10 @@
 // Global hashmap to track valid pointers, this is a safety precaution to make sure we are not
 // reading from unsafe memory address's passed in by caller.
 lazy_static! {
-    static ref HANDLE_MAP: Mutex<HandleMap<Box<LdtAdvDecrypter>>> = Mutex::new(HandleMap::init());
+    static ref ENCRYPT_HANDLE_MAP: Mutex<HandleMap<Box<LdtAdvEncrypter>>> =
+        Mutex::new(HandleMap::init());
+    static ref DECRYPT_HANDLE_MAP: Mutex<HandleMap<Box<LdtAdvDecrypter>>> =
+        Mutex::new(HandleMap::init());
 }
 
 impl<T> HandleMap<T> {
diff --git a/nearby/presence/ldt_np_adv_ffi/src/lib.rs b/nearby/presence/ldt_np_adv_ffi/src/lib.rs
index ddf7f3f..7b440e4 100644
--- a/nearby/presence/ldt_np_adv_ffi/src/lib.rs
+++ b/nearby/presence/ldt_np_adv_ffi/src/lib.rs
@@ -30,17 +30,20 @@
 
 extern crate alloc;
 
+use crate::handle_map::get_dec_handle_map;
 use alloc::boxed::Box;
 use core::slice;
-use handle_map::get_handle_map;
+use handle_map::get_enc_handle_map;
 use ldt_np_adv::{
-    salt_padder, LdtAdvCipherConfig, LdtAdvDecryptError, LdtAdvDecrypterAes128, LegacySalt,
+    build_np_adv_decrypter_from_key_seed, salt_padder, LdtAdvDecryptError, LdtEncrypterXtsAes128,
+    LdtNpAdvDecrypterXtsAes128, LegacySalt,
 };
+use np_hkdf::NpKeySeedHkdf;
 
 // Pull in the needed deps for std vs no_std
 cfg_if::cfg_if! {
     // Test pulls in std which causes duplicate errors
-    if #[cfg(any(feature = "std", test))] {
+    if #[cfg(any(feature = "std", test, feature = "boringssl", feature = "openssl"))] {
         extern crate std;
     } else {
         // Allow using Box in no_std
@@ -48,20 +51,27 @@
     }
 }
 
-// Fail early for invalid combination of feature flags, we need at least on crypto library specified
-#[cfg(all(not(feature = "openssl"), not(feature = "crypto_provider_rustcrypto")))]
-compile_error!("Either the \"openssl\" or \"default\" features flag needs to be set uin order to specify cryptographic library");
+// Fail early for invalid combination of feature flags, we need at least one crypto library specified
+#[cfg(all(
+    not(feature = "openssl"),
+    not(feature = "crypto_provider_rustcrypto"),
+    not(feature = "boringssl")
+))]
+compile_error!("Either the \"openssl\", \"boringssl\"or \"default\" features flag needs to be set in order to specify cryptographic library");
 
 // Need to have one of the crypto provider impls
 cfg_if::cfg_if! {
     if #[cfg(feature = "openssl")] {
         use crypto_provider_openssl::Openssl as CryptoProviderImpl;
+    } else if #[cfg(feature = "boringssl")]{
+        use crypto_provider_boringssl::Boringssl as CryptoProviderImpl;
     } else {
         use crypto_provider_rustcrypto::RustCrypto as CryptoProviderImpl;
     }
 }
 
-pub(crate) type LdtAdvDecrypter = LdtAdvDecrypterAes128<CryptoProviderImpl>;
+pub(crate) type LdtAdvDecrypter = LdtNpAdvDecrypterXtsAes128<CryptoProviderImpl>;
+pub(crate) type LdtAdvEncrypter = LdtEncrypterXtsAes128<CryptoProviderImpl>;
 
 const SUCCESS: i32 = 0;
 
@@ -80,18 +90,53 @@
     bytes: [u8; 2],
 }
 
-#[no_mangle]
-extern "C" fn NpLdtCreate(key_seed: NpLdtKeySeed, metadata_key_hmac: NpMetadataKeyHmac) -> u64 {
-    let ldt_adv_cipher_config = LdtAdvCipherConfig::new(key_seed.bytes, metadata_key_hmac.bytes);
-    let cipher = ldt_adv_cipher_config.build_adv_decrypter_xts_aes_128::<CryptoProviderImpl>();
-    get_handle_map().insert::<CryptoProviderImpl>(Box::new(cipher))
+#[repr(C)]
+struct NpLdtEncryptHandle {
+    handle: u64,
+}
+
+#[repr(C)]
+struct NpLdtDecryptHandle {
+    handle: u64,
 }
 
 #[no_mangle]
-extern "C" fn NpLdtClose(handle: u64) -> i32 {
+extern "C" fn NpLdtDecryptCreate(
+    key_seed: NpLdtKeySeed,
+    metadata_key_hmac: NpMetadataKeyHmac,
+) -> NpLdtDecryptHandle {
+    let cipher = build_np_adv_decrypter_from_key_seed(
+        &NpKeySeedHkdf::new(&key_seed.bytes),
+        metadata_key_hmac.bytes,
+    );
+    let handle = get_dec_handle_map().insert::<CryptoProviderImpl>(Box::new(cipher));
+    NpLdtDecryptHandle { handle }
+}
+
+#[no_mangle]
+extern "C" fn NpLdtEncryptCreate(key_seed: NpLdtKeySeed) -> NpLdtEncryptHandle {
+    let cipher = LdtAdvEncrypter::new(
+        &NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed.bytes).legacy_ldt_key(),
+    );
+    let handle = get_enc_handle_map().insert::<CryptoProviderImpl>(Box::new(cipher));
+    NpLdtEncryptHandle { handle }
+}
+
+#[no_mangle]
+extern "C" fn NpLdtEncryptClose(handle: NpLdtEncryptHandle) -> i32 {
     map_to_error_code(|| {
-        get_handle_map()
-            .remove(&handle)
+        get_enc_handle_map()
+            .remove(&handle.handle)
+            .ok_or(CloseCipherError::InvalidHandle)
+            .map(|_| 0)
+    })
+}
+
+#[no_mangle]
+extern "C" fn NpLdtDecryptClose(handle: NpLdtDecryptHandle) -> i32 {
+    map_to_error_code(|| {
+        get_dec_handle_map()
+            .remove(&handle.handle)
             .ok_or(CloseCipherError::InvalidHandle)
             .map(|_| 0)
     })
@@ -102,7 +147,7 @@
 // and get rid of this.
 #[allow(deprecated)]
 extern "C" fn NpLdtEncrypt(
-    handle: u64,
+    handle: NpLdtEncryptHandle,
     buffer: *mut u8,
     buffer_len: usize,
     salt: NpLdtSalt,
@@ -110,8 +155,8 @@
     map_to_error_code(|| {
         let data = unsafe { slice::from_raw_parts_mut(buffer, buffer_len) };
         let padder = salt_padder::<16, CryptoProviderImpl>(LegacySalt::from(salt.bytes));
-        get_handle_map()
-            .get(&handle)
+        get_enc_handle_map()
+            .get(&handle.handle)
             .map(|cipher| {
                 cipher
                     .encrypt(data, &padder)
@@ -126,7 +171,7 @@
 
 #[no_mangle]
 extern "C" fn NpLdtDecryptAndVerify(
-    handle: u64,
+    handle: NpLdtDecryptHandle,
     buffer: *mut u8,
     buffer_len: usize,
     salt: NpLdtSalt,
@@ -135,8 +180,8 @@
         let data = unsafe { slice::from_raw_parts_mut(buffer, buffer_len) };
         let padder = salt_padder::<16, CryptoProviderImpl>(LegacySalt::from(salt.bytes));
 
-        get_handle_map()
-            .get(&handle)
+        get_dec_handle_map()
+            .get(&handle.handle)
             .map(|cipher| {
                 cipher
                     .decrypt_and_verify(data, &padder)
diff --git a/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_bad_mac.c b/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_bad_mac.c
index 3e8e6ac..18abb0f 100644
--- a/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_bad_mac.c
+++ b/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_bad_mac.c
@@ -53,23 +53,30 @@
   memcpy(&metadata_key_hmac.bytes, data + 32 + 2 + 31 + 1, 32);
 
   // create a cipher
-  NpLdtHandle handle = NpLdtCreate(key_seed, metadata_key_hmac);
-  if (handle == 0) {
-    printf("Error: create LDT\n");
+  NpLdtEncryptHandle enc_handle = NpLdtEncryptCreate(key_seed);
+  if (enc_handle.handle == 0) {
+    printf("Error: create LDT failed\n");
     __builtin_trap();
     return 0;
   }
 
   // encrypt with it
-  NP_LDT_RESULT result = NpLdtEncrypt(handle, payload, payload_len, salt);
+  NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, payload, payload_len, salt);
   if (result != 0) {
     printf("Error: encrypt\n");
     __builtin_trap();
     return 0;
   }
 
+  NpLdtDecryptHandle dec_handle = NpLdtDecryptCreate(key_seed, metadata_key_hmac);
+  if (dec_handle.handle == 0) {
+    printf("Error: create LDT failed\n");
+    __builtin_trap();
+    return 0;
+  }
+
   // decrypt & verify -- we expect mac mismatch since we're using a random mac
-  result = NpLdtDecryptAndVerify(handle, payload, payload_len, salt);
+  result = NpLdtDecryptAndVerify(dec_handle, payload, payload_len, salt);
   if (result != -2) {
     printf("Error: decryption didn't fail with the expected MAC mismatch\n");
     __builtin_trap();
@@ -77,12 +84,19 @@
   }
 
   // deallocate the cipher
-  result = NpLdtClose(handle);
+  result = NpLdtEncryptClose(enc_handle);
   if (result) {
     printf("Error: close cipher\n");
     __builtin_trap();
     return result;
   }
 
+  result = NpLdtDecryptClose(dec_handle);
+  if (result) {
+    printf("Error: close cipher failed\n");
+    __builtin_trap();
+    return result;
+  }
+
   return 0;  // Values other than 0 and -1 are reserved for future use.
 }
diff --git a/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_correct_mac.c b/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_correct_mac.c
index 7d16894..e99a7e8 100644
--- a/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_correct_mac.c
+++ b/nearby/presence/ldt_np_adv_ffi_fuzz/src/fuzzer_decrypt_correct_mac.c
@@ -96,31 +96,45 @@
        metadata_key_hmac.bytes, &md_len);
 
   // create a cipher
-  NpLdtHandle handle = NpLdtCreate(key_seed, metadata_key_hmac);
-  if (handle == 0) {
+  NpLdtEncryptHandle enc_handle = NpLdtEncryptCreate(key_seed);
+  if (enc_handle.handle == 0) {
     printf("Error: create LDT failed\n");
     __builtin_trap();
     return 0;
   }
 
   // encrypt with it
-  NP_LDT_RESULT result = NpLdtEncrypt(handle, payload, payload_len, salt);
+  NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, payload, payload_len, salt);
   if (result != 0) {
     printf("Error: encrypt\n");
     __builtin_trap();
     return 0;
   }
 
+  NpLdtDecryptHandle dec_handle = NpLdtDecryptCreate(key_seed, metadata_key_hmac);
+  if (dec_handle.handle == 0) {
+    printf("Error: create LDT failed\n");
+    __builtin_trap();
+    return 0;
+  }
+
   // decrypt & verify -- we expect mac mismatch since we're using a random mac
-  result = NpLdtDecryptAndVerify(handle, payload, payload_len, salt);
+  result = NpLdtDecryptAndVerify(dec_handle, payload, payload_len, salt);
   if (result != 0) {
     printf("Error: decryption failed\n");
     __builtin_trap();
     return 0;
   }
 
-  // deallocate the cipher
-  result = NpLdtClose(handle);
+  // deallocate the ciphers
+  result = NpLdtEncryptClose(enc_handle);
+  if (result) {
+    printf("Error: close cipher failed\n");
+    __builtin_trap();
+    return result;
+  }
+
+  result = NpLdtDecryptClose(dec_handle);
   if (result) {
     printf("Error: close cipher failed\n");
     __builtin_trap();
diff --git a/nearby/presence/ldt_np_c_sample/CMakeLists.txt b/nearby/presence/ldt_np_c_sample/CMakeLists.txt
index b4d149a..58b6f6f 100644
--- a/nearby/presence/ldt_np_c_sample/CMakeLists.txt
+++ b/nearby/presence/ldt_np_c_sample/CMakeLists.txt
@@ -24,7 +24,7 @@
     ldt_np_adv_ffi
     DOWNLOAD_COMMAND ""
     CONFIGURE_COMMAND ""
-    BUILD_COMMAND cargo build COMMAND cargo build --release
+    BUILD_COMMAND cargo build COMMAND cargo build --release --no-default-features --features std
     BINARY_DIR "${CMAKE_SOURCE_DIR}/ldt_np_adv_ffi"
     INSTALL_COMMAND "")
 
diff --git a/nearby/presence/ldt_np_c_sample/main.c b/nearby/presence/ldt_np_c_sample/main.c
index 4bfbb79..1ae9244 100644
--- a/nearby/presence/ldt_np_c_sample/main.c
+++ b/nearby/presence/ldt_np_c_sample/main.c
@@ -41,11 +41,10 @@
         {12, 15}
     };
 
-    // Create handle
-    NpLdtHandle handle = NpLdtCreate(*key_seed, *known_hmac);
-    if (handle == 0)
+    // Create handle for encryption
+    NpLdtEncryptHandle enc_handle = NpLdtEncryptCreate(*key_seed);
+    if (enc_handle.handle == 0)
     {
-        printf("Invalid alignment\n");
         return -1;
     }
 
@@ -57,7 +56,7 @@
     printf("\n");
 
     // Encrypt the data and print it
-    NP_LDT_RESULT result = NpLdtEncrypt(handle, plaintext, 24, salt);
+    NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, plaintext, 24, salt);
     if (result)
     {
         printf("Error in NpLdtEncrypt: %d\n", result);
@@ -69,8 +68,15 @@
         printf("%X ", *(plaintext + i));
     printf("\n");
 
+    // Create handle for encryption
+    NpLdtDecryptHandle dec_handle = NpLdtDecryptCreate(*key_seed, *known_hmac);
+    if (enc_handle.handle == 0)
+    {
+        return -1;
+    }
+
     // Decrypt the data and print its bytes
-    result = NpLdtDecryptAndVerify(handle, plaintext, 24, salt);
+    result = NpLdtDecryptAndVerify(dec_handle, plaintext, 24, salt);
     if (result)
     {
         printf("Error in NpDecryptAndVerify: %d\n", result);
@@ -83,7 +89,15 @@
     printf("\n");
 
     // Call NpLdtClose to free resources
-    result = NpLdtClose(handle);
+    result = NpLdtEncryptClose(enc_handle);
+    if (result)
+    {
+        printf("Error in NpLdtClose: %d\n", result);
+        return result;
+    }
+
+    // Call NpLdtClose to free resources
+    result = NpLdtDecryptClose(dec_handle);
     if (result)
     {
         printf("Error in NpLdtClose: %d\n", result);
diff --git a/nearby/presence/ldt_np_c_sample/tests/benchmarks.cc b/nearby/presence/ldt_np_c_sample/tests/benchmarks.cc
index d84c304..fbd20a8 100644
--- a/nearby/presence/ldt_np_c_sample/tests/benchmarks.cc
+++ b/nearby/presence/ldt_np_c_sample/tests/benchmarks.cc
@@ -37,7 +37,7 @@
     size_t payload_len;
     uint8_t* payload;
     NpLdtSalt* salt;
-    vector<NpLdtHandle> handles;
+    vector<tuple<NpLdtEncryptHandle, NpLdtDecryptHandle>> handles;
     vector<tuple<NpLdtKeySeed*, NpMetadataKeyHmac*>> configs;
 
     void SetUp(const ::benchmark::State& state)
@@ -63,23 +63,20 @@
     {
         for(int i = 0; i < num_ciphers; i++)
         {
-            NpLdtHandle handle = buildCipherFromRand();
-            handles.push_back(handle);
+            NpLdtKeySeed* key_seed = (NpLdtKeySeed*) malloc(sizeof(NpLdtKeySeed));
+            NpMetadataKeyHmac* known_hmac = (NpMetadataKeyHmac*) malloc(sizeof(NpMetadataKeyHmac));
+
+            generateRandomBytes(key_seed->bytes, 32);
+            generateRandomBytes(known_hmac->bytes, 32);
+
+            configs.push_back(tuple<NpLdtKeySeed*, NpMetadataKeyHmac*>(key_seed, known_hmac));
+            auto enc_handle = NpLdtEncryptCreate(*key_seed);
+            auto dec_handle = NpLdtDecryptCreate(*key_seed, *known_hmac);
+
+            handles.push_back(tuple<NpLdtEncryptHandle, NpLdtDecryptHandle>(enc_handle, dec_handle));
         }
     }
 
-    NpLdtHandle buildCipherFromRand()
-    {
-        NpLdtKeySeed* key_seed = (NpLdtKeySeed*) malloc(sizeof(NpLdtKeySeed));
-        NpMetadataKeyHmac* known_hmac = (NpMetadataKeyHmac*) malloc(sizeof(NpMetadataKeyHmac));
-
-        generateRandomBytes(key_seed->bytes, 32);
-        generateRandomBytes(known_hmac->bytes, 32);
-
-        configs.push_back(tuple<NpLdtKeySeed*, NpMetadataKeyHmac*>(key_seed, known_hmac));
-        return NpLdtCreate(*key_seed, *known_hmac);
-    }
-
     void generatePayload()
     {
         payload_len = randNumInRange(BLOCK_SIZE, LDT_PAYLOAD_MAX_LEN);
@@ -100,9 +97,13 @@
 
     void freeCiphers()
     {
-        for(NpLdtHandle handle : handles)
+        for(tuple<NpLdtEncryptHandle, NpLdtDecryptHandle> handle : handles)
         {
-            NpLdtClose(handle);
+            auto enc_handle = std::get<0>(handle);
+            NpLdtEncryptClose(enc_handle);
+
+            auto dec_handle = std::get<1>(handle);
+            NpLdtDecryptClose(dec_handle);
         }
     }
 
@@ -120,9 +121,10 @@
 {
     for (auto _ : state)
     {
-        for(NpLdtHandle handle : handles)
+        for(tuple<NpLdtEncryptHandle, NpLdtDecryptHandle> handle : handles)
         {
-            NpLdtDecryptAndVerify(handle, payload, payload_len, *salt);
+            auto dec_handle = std::get<1>(handle);
+            NpLdtDecryptAndVerify(dec_handle, payload, payload_len, *salt);
         }
     }
 };
@@ -135,7 +137,7 @@
     {
         for(tuple<NpLdtKeySeed*, NpMetadataKeyHmac*> values : configs)
         {
-            NpLdtHandle handle = NpLdtCreate(*std::get<0>(values), *std::get<1>(values));
+            NpLdtDecryptHandle handle = NpLdtDecryptCreate(*std::get<0>(values), *std::get<1>(values));
             NpLdtDecryptAndVerify(handle, payload, payload_len, *salt);
         }
     }
diff --git a/nearby/presence/ldt_np_c_sample/tests/np_ffi_tests.cc b/nearby/presence/ldt_np_c_sample/tests/np_ffi_tests.cc
index 3e20338..fbb0db4 100644
--- a/nearby/presence/ldt_np_c_sample/tests/np_ffi_tests.cc
+++ b/nearby/presence/ldt_np_c_sample/tests/np_ffi_tests.cc
@@ -40,7 +40,15 @@
     {12, 15}
 };
 
-static NpLdtHandle create_handle_from_test_key ()
+static NpLdtEncryptHandle create_enc_handle_from_test_key ()
+{
+    NpLdtKeySeed key_seed;
+    memcpy(key_seed.bytes, KEY_SEED_BYTES, 32);
+
+    return NpLdtEncryptCreate(key_seed);
+}
+
+static NpLdtDecryptHandle create_dec_handle_from_test_key ()
 {
     NpLdtKeySeed key_seed;
     memcpy(key_seed.bytes, KEY_SEED_BYTES, 32);
@@ -48,7 +56,7 @@
     NpMetadataKeyHmac known_hmac;
     memcpy(known_hmac.bytes, KNOWN_HMAC_BYTES, 32);
 
-    return NpLdtCreate(key_seed, known_hmac);
+    return NpLdtDecryptCreate(key_seed, known_hmac);
 }
 
 static void hex_string_to_bytes(const char * hexString, uint8_t * out, size_t len)
@@ -105,8 +113,8 @@
         hex_string_to_bytes(metadata_key_hmac, known_hmac.bytes, len);
         ASSERT_EQ(len, 32);
 
-        NpLdtHandle handle = NpLdtCreate(np_key_seed, known_hmac);
-        ASSERT_NE(handle, 0);
+        NpLdtEncryptHandle enc_handle = NpLdtEncryptCreate(np_key_seed);
+        ASSERT_NE(enc_handle.handle, 0);
 
         NpLdtSalt salt;
         len = strlen(adv_salt)/2;
@@ -116,14 +124,17 @@
         len = strlen(plaintext)/2;
         uint8_t* buffer = (uint8_t*)malloc(len);
         hex_string_to_bytes(plaintext, buffer, len);
-        NP_LDT_RESULT result = NpLdtEncrypt(handle, buffer, len, salt);
+        NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, buffer, len, salt);
         ASSERT_EQ(result, NP_LDT_SUCCESS);
 
         char output[strlen(plaintext) + 1];
         bytes_to_hex_string(buffer, output, len);
         ASSERT_EQ(strcmp(output, ciphertext), 0);
 
-        result = NpLdtDecryptAndVerify(handle, buffer, len, salt);
+        NpLdtDecryptHandle dec_handle = NpLdtDecryptCreate(np_key_seed, known_hmac);
+        ASSERT_NE(dec_handle.handle, 0);
+
+        result = NpLdtDecryptAndVerify(dec_handle, buffer, len, salt);
         ASSERT_EQ(result, NP_LDT_SUCCESS);
 
         bytes_to_hex_string(buffer, output, len);
@@ -139,13 +150,15 @@
     uint8_t* plaintext = (uint8_t*) malloc(20 * sizeof(uint8_t));
     memcpy(plaintext, TEST_DATA_BYTES, 20);
 
-    NpLdtHandle handle = create_handle_from_test_key();
-    ASSERT_NE(handle, 0);
+    NpLdtEncryptHandle enc_handle = create_enc_handle_from_test_key();
+    ASSERT_NE(enc_handle.handle, 0);
 
-    NP_LDT_RESULT result = NpLdtEncrypt(handle, plaintext, 20, salt);
+    NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, plaintext, 20, salt);
     ASSERT_EQ(result, NP_LDT_SUCCESS);
 
-    result = NpLdtDecryptAndVerify(handle, plaintext, 20, salt);
+    NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+
+    result = NpLdtDecryptAndVerify(dec_handle, plaintext, 20, salt);
     ASSERT_EQ(result, NP_LDT_SUCCESS);
     free(plaintext);
 }
@@ -155,13 +168,13 @@
     uint8_t* plaintext = (uint8_t*) malloc(32 * sizeof(uint8_t));
     memcpy(plaintext, TEST_DATA_BYTES, 20);
 
-    NpLdtHandle handle = create_handle_from_test_key();
-    ASSERT_NE(handle, 0);
+    NpLdtEncryptHandle enc_handle = create_enc_handle_from_test_key();
+    ASSERT_NE(enc_handle.handle, 0);
 
-    NP_LDT_RESULT result = NpLdtEncrypt(handle, plaintext, 32, salt);
+    NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, plaintext, 32, salt);
     ASSERT_EQ(result, NP_LDT_ERROR_INVALID_LENGTH);
 
-    result = NpLdtEncrypt(handle, plaintext, 15, salt);
+    result = NpLdtEncrypt(enc_handle, plaintext, 15, salt);
     ASSERT_EQ(result,  NP_LDT_ERROR_INVALID_LENGTH);
     free(plaintext);
 }
@@ -171,13 +184,13 @@
     uint8_t* plaintext = (uint8_t*) malloc(32 * sizeof(uint8_t));
     memcpy(plaintext, TEST_DATA_BYTES, 20);
 
-    NpLdtHandle handle = create_handle_from_test_key();
-    ASSERT_NE(handle, 0);
+    NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+    ASSERT_NE(dec_handle.handle, 0);
 
-    NP_LDT_RESULT result = NpLdtDecryptAndVerify(handle, plaintext, 32, salt);
+    NP_LDT_RESULT result = NpLdtDecryptAndVerify(dec_handle, plaintext, 32, salt);
     ASSERT_EQ(result, NP_LDT_ERROR_INVALID_LENGTH);
 
-    result = NpLdtDecryptAndVerify(handle, plaintext, 15, salt);
+    result = NpLdtDecryptAndVerify(dec_handle, plaintext, 15, salt);
     ASSERT_EQ(result, NP_LDT_ERROR_INVALID_LENGTH);
     free(plaintext);
 }
@@ -189,10 +202,10 @@
     uint8_t* plaintext = (uint8_t*) malloc(30 * sizeof(char));
     memcpy(plaintext, test_text, 29);
 
-    NpLdtHandle handle = create_handle_from_test_key();
-    ASSERT_NE(handle, 0);
+    NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+    ASSERT_NE(dec_handle.handle, 0);
 
-    NP_LDT_RESULT result = NpLdtDecryptAndVerify(handle, plaintext, 24, salt);
+    NP_LDT_RESULT result = NpLdtDecryptAndVerify(dec_handle, plaintext, 24, salt);
     ASSERT_EQ(result, NP_LDT_ERROR_MAC_MISMATCH);
 
     ASSERT_EQ(strcmp((char *)plaintext, test_text), 0);
@@ -204,17 +217,17 @@
     uint8_t* plaintext = (uint8_t*) malloc(20 * sizeof(uint8_t));
     memcpy(plaintext, TEST_DATA_BYTES, 20);
 
-    NpLdtHandle handle = create_handle_from_test_key();
-    ASSERT_NE(handle, 0);
-
-    NP_LDT_RESULT result = NpLdtEncrypt(1234, plaintext, 20, salt);
+    NP_LDT_RESULT result = NpLdtEncrypt(NpLdtEncryptHandle{1234}, plaintext, 20, salt);
     ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
 
-    result = NpLdtDecryptAndVerify(1234, plaintext, 20, salt);
+    result = NpLdtDecryptAndVerify(NpLdtDecryptHandle{1234}, plaintext, 20, salt);
     ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
     free(plaintext);
 
-    result = NpLdtClose(1234);
+    result = NpLdtEncryptClose(NpLdtEncryptHandle{1234});
+    ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
+
+    result = NpLdtDecryptClose(NpLdtDecryptHandle{1234});
     ASSERT_EQ(result, NP_LDT_INVALID_HANDLE);
 }
 
@@ -235,21 +248,27 @@
     uint8_t* plaintext = (uint8_t*) malloc(20 * sizeof(uint8_t));
     memcpy(plaintext, TEST_DATA_BYTES, 20);
 
-    NpLdtHandle handle = create_handle_from_test_key();
-    if (handle == 0){
+    NpLdtEncryptHandle enc_handle = create_enc_handle_from_test_key();
+    if (enc_handle.handle == 0){
         printf("Error creating handle in thread!");
         free(plaintext);
         exit(2);
     }
 
-    NP_LDT_RESULT result = NpLdtEncrypt(handle, plaintext, 20, salt);
+    NP_LDT_RESULT result = NpLdtEncrypt(enc_handle, plaintext, 20, salt);
     if (result != NP_LDT_SUCCESS){
         printf("Error in encrypt in thread!");
         free(plaintext);
         exit(2);
     }
 
-    result = NpLdtDecryptAndVerify(handle, plaintext, 20, salt);
+    NpLdtDecryptHandle dec_handle = create_dec_handle_from_test_key();
+    if (dec_handle.handle == 0){
+        printf("Error creating handle in thread!");
+        free(plaintext);
+        exit(2);
+    }
+    result = NpLdtDecryptAndVerify(dec_handle, plaintext, 20, salt);
     if (result != NP_LDT_SUCCESS){
         printf("Error in decrypt in thread!");
         free(plaintext);
diff --git a/nearby/presence/ldt_tbc/src/lib.rs b/nearby/presence/ldt_tbc/src/lib.rs
index 8a07f48..97dc5a5 100644
--- a/nearby/presence/ldt_tbc/src/lib.rs
+++ b/nearby/presence/ldt_tbc/src/lib.rs
@@ -23,20 +23,45 @@
 
 //! Defining traits for an LDT specific Tweakable Block Cipher
 
-/// `B` is the block size in bytes.
+/// The higher level trait defining the single block at a time Tweakable Block Cipher types.
+/// Holds associates types for both the [TweakableBlockCipherEncrypter] and corresponding
+/// [TweakableBlockCipherDecrypter]
 pub trait TweakableBlockCipher<const B: usize> {
+    /// The tweakable block cipher encryption cipher
+    type EncryptionCipher: TweakableBlockCipherEncrypter<B, Key = Self::Key, Tweak = Self::Tweak>;
+
+    /// The tweakable block cipher decryption cipher
+    type DecryptionCipher: TweakableBlockCipherDecrypter<B, Key = Self::Key, Tweak = Self::Tweak>;
+
     /// The tweak type used with encryption/decryption.
     type Tweak: From<[u8; B]>;
 
     /// the tweakable block cipher key type for the tbc
     type Key: TweakableBlockCipherKey;
+}
 
-    /// Create a new tweakable block cipher for ldt from a tbc key
+/// Trait defining a Tweakable Block Cipher, single block at a time, decrypt operation
+/// `B` is the block size in bytes.
+pub trait TweakableBlockCipherEncrypter<const B: usize> {
+    /// The tweakable block cipher key type for the tbc
+    type Key: TweakableBlockCipherKey;
+    /// The tweak type used when encrypting
+    type Tweak: From<[u8; B]>;
+    /// Build a [TweakableBlockCipherEncrypter] with the provided and the provided key.
     fn new(key: &Self::Key) -> Self;
-
     /// Encrypt `block` in place using the specified `tweak`.
     fn encrypt(&self, tweak: Self::Tweak, block: &mut [u8; B]);
+}
 
+/// Trait defining a Tweakable Block Cipher, single block at a time, encrypt operation
+/// `B` is the block size in bytes.
+pub trait TweakableBlockCipherDecrypter<const B: usize> {
+    /// The tweakable block cipher key type for the tbc
+    type Key: TweakableBlockCipherKey;
+    /// The tweak type used when decrypting
+    type Tweak: From<[u8; B]>;
+    /// Build a [TweakableBlockCipherDecrypter] with the provided and the provided key.
+    fn new(key: &Self::Key) -> Self;
     /// Decrypt `block` in place using the specified `tweak`.
     fn decrypt(&self, tweak: Self::Tweak, block: &mut [u8; B]);
 }
diff --git a/nearby/presence/np_hkdf/src/v1_salt.rs b/nearby/presence/np_hkdf/src/v1_salt.rs
index 6fb309f..acd118c 100644
--- a/nearby/presence/np_hkdf/src/v1_salt.rs
+++ b/nearby/presence/np_hkdf/src/v1_salt.rs
@@ -59,6 +59,11 @@
     pub fn as_slice(&self) -> &[u8] {
         self.data.as_slice()
     }
+
+    /// Returns the salt bytes as a reference to an array
+    pub fn as_array_ref(&self) -> &[u8; 16] {
+        &self.data
+    }
 }
 
 impl<C: CryptoProvider> From<[u8; 16]> for V1Salt<C> {
diff --git a/nearby/presence/test_helper/src/lib.rs b/nearby/presence/test_helper/src/lib.rs
index e095d36..ecb54c9 100644
--- a/nearby/presence/test_helper/src/lib.rs
+++ b/nearby/presence/test_helper/src/lib.rs
@@ -27,13 +27,20 @@
     full_path
 }
 
-/// Opens a json file at the specified path and parses it into a value
-pub fn parse_json_data_file(file: &str) -> serde_json::Value {
+/// Opens a file at the specified path (relative to the workspace root)
+/// and yields its contents as a string
+pub fn load_data_file_contents_as_string(file: &str) -> String {
     let full_path = get_data_file(file);
     let mut file = fs::File::open(full_path).expect("Should be able to open data file");
     let mut data = String::new();
     file.read_to_string(&mut data)
         .expect("should be able to read data file");
+    data
+}
+
+/// Opens a json file at the specified path and parses it into a value
+pub fn parse_json_data_file(file: &str) -> serde_json::Value {
+    let data = load_data_file_contents_as_string(file);
     serde_json::de::from_str(data.as_str()).expect("should be able to parse json date file")
 }
 
diff --git a/nearby/presence/xts_aes/fuzz/Cargo.lock b/nearby/presence/xts_aes/fuzz/Cargo.lock
index 90fc28c..a03bfe0 100644
--- a/nearby/presence/xts_aes/fuzz/Cargo.lock
+++ b/nearby/presence/xts_aes/fuzz/Cargo.lock
@@ -54,18 +54,9 @@
 
 [[package]]
 name = "base16ct"
-version = "0.1.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
-
-[[package]]
-name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
 
 [[package]]
 name = "block-buffer"
@@ -86,12 +77,6 @@
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
 name = "bytes"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -148,12 +133,12 @@
 
 [[package]]
 name = "crypto-bigint"
-version = "0.4.9"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
+checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
  "zeroize",
 ]
@@ -165,7 +150,7 @@
 checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
 dependencies = [
  "generic-array",
- "rand_core 0.6.4",
+ "rand_core",
  "typenum",
 ]
 
@@ -193,10 +178,9 @@
  "p256",
  "rand",
  "rand_chacha",
- "rand_core 0.6.4",
- "rand_core_05_adapter",
+ "rand_core",
  "sec1",
- "sha2 0.10.6",
+ "sha2",
  "subtle",
  "x25519-dalek",
 ]
@@ -212,24 +196,26 @@
 
 [[package]]
 name = "curve25519-dalek"
-version = "3.2.0"
+version = "4.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
+checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585"
 dependencies = [
- "byteorder",
- "digest 0.9.0",
- "rand_core 0.5.1",
+ "cfg-if",
+ "digest",
+ "fiat-crypto",
+ "packed_simd_2",
+ "platforms",
  "subtle",
- "zeroize",
 ]
 
 [[package]]
 name = "der"
-version = "0.6.1"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
+checksum = "bc906908ea6458456e5eaa160a9c08543ec3d1e6f71e2235cedd660cb65f9df0"
 dependencies = [
  "const-oid",
+ "zeroize",
 ]
 
 [[package]]
@@ -245,60 +231,50 @@
 
 [[package]]
 name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "digest"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
- "block-buffer 0.10.4",
+ "block-buffer",
  "crypto-common",
  "subtle",
 ]
 
 [[package]]
 name = "ed25519"
-version = "1.5.3"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
 dependencies = [
  "signature",
 ]
 
 [[package]]
 name = "ed25519-dalek"
-version = "1.0.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a"
 dependencies = [
  "curve25519-dalek",
  "ed25519",
- "sha2 0.9.9",
- "zeroize",
+ "rand_core",
+ "sha2",
 ]
 
 [[package]]
 name = "elliptic-curve"
-version = "0.12.3"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
+checksum = "6ea5a92946e8614bb585254898bb7dd1ddad241ace60c52149e3765e34cc039d"
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "der",
- "digest 0.10.6",
+ "digest",
  "ff",
  "generic-array",
  "group",
  "hkdf",
- "rand_core 0.6.4",
+ "rand_core",
  "sec1",
  "subtle",
  "zeroize",
@@ -306,15 +282,21 @@
 
 [[package]]
 name = "ff"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
+checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
 dependencies = [
- "rand_core 0.6.4",
+ "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.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -322,6 +304,7 @@
 dependencies = [
  "typenum",
  "version_check",
+ "zeroize",
 ]
 
 [[package]]
@@ -337,12 +320,12 @@
 
 [[package]]
 name = "group"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
 dependencies = [
  "ff",
- "rand_core 0.6.4",
+ "rand_core",
  "subtle",
 ]
 
@@ -361,7 +344,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
@@ -408,6 +391,12 @@
 ]
 
 [[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
+[[package]]
 name = "once_cell"
 version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -421,15 +410,31 @@
 
 [[package]]
 name = "p256"
-version = "0.12.0"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49c124b3cbce43bcbac68c58ec181d98ed6cc7e6d0aa7c3ba97b2563410b0e55"
+checksum = "7270da3e5caa82afd3deb054cc237905853813aea3859544bc082c3fe55b8d47"
 dependencies = [
  "elliptic-curve",
  "primeorder",
 ]
 
 [[package]]
+name = "packed_simd_2"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
+dependencies = [
+ "cfg-if",
+ "libm",
+]
+
+[[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.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -449,9 +454,9 @@
 
 [[package]]
 name = "primeorder"
-version = "0.12.1"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b54f7131b3dba65a2f414cf5bd25b66d4682e4608610668eae785750ba4c5b2"
+checksum = "7613fdcc0831c10060fa69833ea8fa2caa94b6456f51e25356a885b530a2e3d0"
 dependencies = [
  "elliptic-curve",
 ]
@@ -480,7 +485,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
@@ -490,17 +495,11 @@
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.4",
+ "rand_core",
 ]
 
 [[package]]
 name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-
-[[package]]
-name = "rand_core"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
@@ -509,18 +508,10 @@
 ]
 
 [[package]]
-name = "rand_core_05_adapter"
-version = "0.1.0"
-dependencies = [
- "rand",
- "rand_core 0.5.1",
-]
-
-[[package]]
 name = "sec1"
-version = "0.3.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
+checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e"
 dependencies = [
  "base16ct",
  "der",
@@ -531,33 +522,20 @@
 
 [[package]]
 name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer 0.9.0",
- "cfg-if",
- "cpufeatures",
- "digest 0.9.0",
- "opaque-debug",
-]
-
-[[package]]
-name = "sha2"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.6",
+ "digest",
 ]
 
 [[package]]
 name = "signature"
-version = "1.6.4"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
 
 [[package]]
 name = "subtle"
@@ -577,18 +555,6 @@
 ]
 
 [[package]]
-name = "synstructure"
-version = "0.12.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "unicode-xid",
-]
-
-[[package]]
 name = "typenum"
 version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -601,12 +567,6 @@
 checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
 
 [[package]]
-name = "unicode-xid"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
-
-[[package]]
 name = "universal-hash"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -630,13 +590,12 @@
 
 [[package]]
 name = "x25519-dalek"
-version = "2.0.0-pre.1"
+version = "2.0.0-rc.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df"
+checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95"
 dependencies = [
  "curve25519-dalek",
- "rand_core 0.6.4",
- "zeroize",
+ "rand_core",
 ]
 
 [[package]]
@@ -646,6 +605,7 @@
  "arbitrary",
  "crypto_provider",
  "crypto_provider_rustcrypto",
+ "ldt_tbc",
  "libfuzzer-sys",
  "xts_aes",
 ]
@@ -664,18 +624,3 @@
 version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
diff --git a/nearby/presence/xts_aes/fuzz/Cargo.toml b/nearby/presence/xts_aes/fuzz/Cargo.toml
index 70b700f..4d00c49 100644
--- a/nearby/presence/xts_aes/fuzz/Cargo.toml
+++ b/nearby/presence/xts_aes/fuzz/Cargo.toml
@@ -21,6 +21,9 @@
 [dependencies.crypto_provider_rustcrypto]
 path = "../../../crypto/crypto_provider_rustcrypto"
 
+[dependencies.ldt_tbc]
+path = "../../../presence/ldt_tbc"
+
 # Prevent this from interfering with workspaces
 [workspace]
 members = ["."]
diff --git a/nearby/presence/xts_aes/fuzz/fuzz_targets/xts_roundtrip.rs b/nearby/presence/xts_aes/fuzz/fuzz_targets/xts_roundtrip.rs
index 91eaa5c..b7133de 100644
--- a/nearby/presence/xts_aes/fuzz/fuzz_targets/xts_roundtrip.rs
+++ b/nearby/presence/xts_aes/fuzz/fuzz_targets/xts_roundtrip.rs
@@ -13,8 +13,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crypto_provider::CryptoProvider;
 use crypto_provider_rustcrypto::RustCrypto;
+use ldt_tbc::{TweakableBlockCipherDecrypter, TweakableBlockCipherEncrypter};
 use libfuzzer_sys::fuzz_target;
 use xts_aes::*;
 
@@ -24,16 +24,23 @@
         return;
     }
 
-    let xts = build_xts_aes::<_, <RustCrypto as CryptoProvider>::Aes128>(
-        &XtsAes128Key::from(&data.key),
-    );
+    let xts_enc =
+        <XtsAes128<RustCrypto> as ldt_tbc::TweakableBlockCipher<16>>::EncryptionCipher::new(
+            &XtsAes128Key::from(&data.key),
+        );
+    let xts_dec =
+        <XtsAes128<RustCrypto> as ldt_tbc::TweakableBlockCipher<16>>::DecryptionCipher::new(
+            &XtsAes128Key::from(&data.key),
+        );
+
     let tweak: Tweak = data.tweak.into();
 
     let mut buffer = data.plaintext.clone();
 
-    xts.encrypt_data_unit(tweak.clone(), &mut buffer[..])
+    xts_enc
+        .encrypt_data_unit(tweak.clone(), &mut buffer[..])
         .unwrap();
-    xts.decrypt_data_unit(tweak, &mut buffer[..]).unwrap();
+    xts_dec.decrypt_data_unit(tweak, &mut buffer[..]).unwrap();
     assert_eq!(data.plaintext, buffer);
 });
 
diff --git a/nearby/presence/xts_aes/src/lib.rs b/nearby/presence/xts_aes/src/lib.rs
index e213dc2..1ffa813 100644
--- a/nearby/presence/xts_aes/src/lib.rs
+++ b/nearby/presence/xts_aes/src/lib.rs
@@ -29,33 +29,22 @@
 
 use array_ref::{array_mut_ref, array_ref};
 use core::fmt;
+use core::marker::PhantomData;
+
 use crypto_provider::aes::{Aes, AesCipher, AesDecryptCipher, AesEncryptCipher};
 use crypto_provider::{
     aes::{AesKey, BLOCK_SIZE},
     CryptoProvider,
 };
 
-use ldt_tbc::{TweakableBlockCipher, TweakableBlockCipherKey};
+use ldt_tbc::{
+    TweakableBlockCipher, TweakableBlockCipherDecrypter, TweakableBlockCipherEncrypter,
+    TweakableBlockCipherKey,
+};
 
 #[cfg(test)]
 mod tweak_tests;
 
-/// Build an [Xts] with the provided [Aes] with separate block cipher keys.
-fn build_xts_aes_separate<A: Aes>(key1: &A::Key, key2: &A::Key) -> Xts<A> {
-    // TODO: split xts into encrypter and decrypter for better performance
-    Xts {
-        main_encryption_cipher: A::EncryptCipher::new(key1),
-        main_decryption_cipher: A::DecryptCipher::new(key1),
-        tweak_encryption_cipher: A::EncryptCipher::new(key2),
-        tweak_decryption_cipher: A::DecryptCipher::new(key2),
-    }
-}
-
-/// Build an [Xts] with the provided [Aes] and the provided key.
-pub fn build_xts_aes<K: XtsKey, A: Aes<Key = K::BlockCipherKey>>(key: &K) -> Xts<A> {
-    build_xts_aes_separate::<A>(key.key_1(), key.key_2())
-}
-
 /// XTS-AES as per NIST docs
 /// [here](https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/1619-2007-NIST-Submission.pdf)
 /// and
@@ -75,27 +64,51 @@
 /// the tweak used to encrypt that block.
 ///
 /// There is no support for partial bytes (bit lengths that aren't a multiple of 8).
-#[repr(C)]
-pub struct Xts<A: Aes> {
-    main_encryption_cipher: A::EncryptCipher,
-    main_decryption_cipher: A::DecryptCipher,
-    tweak_encryption_cipher: A::EncryptCipher,
-    tweak_decryption_cipher: A::DecryptCipher,
+pub struct XtsAes<A: Aes<Key = K::BlockCipherKey>, K: XtsKey + TweakableBlockCipherKey> {
+    _marker: PhantomData<A>,
+    _marker2: PhantomData<K>,
 }
 
-type DataUnitPartsResult<'a> = Result<(&'a mut [u8], &'a mut [u8], &'a mut [u8]), XtsError>;
+impl<A: Aes<Key = K::BlockCipherKey>, K: XtsKey + TweakableBlockCipherKey>
+    TweakableBlockCipher<BLOCK_SIZE> for XtsAes<A, K>
+{
+    type EncryptionCipher = XtsEncrypter<A, K>;
+    type DecryptionCipher = XtsDecrypter<A, K>;
+    type Tweak = Tweak;
+    type Key = K;
+}
 
-// We have vetted each instance is used in a context where the slice will
-// always be in range, and the expects are unreachable
+/// The XtsAes128 implementation
+pub type XtsAes128<C> = XtsAes<<C as CryptoProvider>::Aes128, XtsAes128Key>;
+
+/// The XtsAes256 implementation
+pub type XtsAes256<C> = XtsAes<<C as CryptoProvider>::Aes256, XtsAes256Key>;
+
+/// Struct which provides Xts Aes Encrypt operations
+#[repr(C)]
+pub struct XtsEncrypter<A: Aes<Key = K::BlockCipherKey>, K: XtsKey> {
+    main_encryption_cipher: A::EncryptCipher,
+    tweak_encryption_cipher: A::EncryptCipher,
+    _marker: PhantomData<K>,
+}
+
+/// Struct which provides Xts Aes Decrypt operations
+#[repr(C)]
+pub struct XtsDecrypter<A: Aes<Key = K::BlockCipherKey>, K: XtsKey> {
+    main_decryption_cipher: A::DecryptCipher,
+    tweak_encryption_cipher: A::EncryptCipher,
+    _marker: PhantomData<K>,
+}
+
 #[allow(clippy::expect_used)]
 #[allow(clippy::indexing_slicing)]
-impl<A: Aes> Xts<A> {
+impl<A: Aes<Key = K::BlockCipherKey>, K: XtsKey> XtsEncrypter<A, K> {
     /// Encrypt a data unit in place, using sequential block numbers for each block.
     /// `data_unit` must be at least [BLOCK_SIZE] bytes, and fewer than
     /// `BLOCK_SIZE * 2^20` bytes.
     pub fn encrypt_data_unit(&self, tweak: Tweak, data_unit: &mut [u8]) -> Result<(), XtsError> {
         let (standalone_blocks, last_complete_block, partial_last_block) =
-            Self::data_unit_parts(data_unit)?;
+            data_unit_parts(data_unit)?;
 
         let mut tweaked_xts = self.tweaked(tweak);
 
@@ -157,12 +170,27 @@
         Ok(())
     }
 
+    /// Returns an [XtsTweaked] configured with the specified tweak and a block number of 0.
+    fn tweaked(&self, tweak: Tweak) -> XtsEncrypterTweaked<A> {
+        let mut bytes = tweak.bytes;
+        self.tweak_encryption_cipher.encrypt(&mut bytes);
+
+        XtsEncrypterTweaked {
+            tweak_state: TweakState::new(bytes),
+            enc_cipher: &self.main_encryption_cipher,
+        }
+    }
+}
+
+#[allow(clippy::expect_used)]
+#[allow(clippy::indexing_slicing)]
+impl<A: Aes<Key = K::BlockCipherKey>, K: XtsKey> XtsDecrypter<A, K> {
     /// Decrypt a data unit in place, using sequential block numbers for each block.
     /// `data_unit` must be at least [BLOCK_SIZE] bytes, and fewer than
     /// `BLOCK_SIZE * 2^20` bytes.
     pub fn decrypt_data_unit(&self, tweak: Tweak, data_unit: &mut [u8]) -> Result<(), XtsError> {
         let (standalone_blocks, last_complete_block, partial_last_block) =
-            Self::data_unit_parts(data_unit)?;
+            data_unit_parts(data_unit)?;
 
         let mut tweaked_xts = self.tweaked(tweak);
 
@@ -213,94 +241,80 @@
         Ok(())
     }
 
-    /// Returns `(standalone blocks, last complete block, partial last block)`.
-    fn data_unit_parts(data_unit: &mut [u8]) -> DataUnitPartsResult {
-        if data_unit.len() < BLOCK_SIZE {
-            return Err(XtsError::DataTooShort);
-        } else if data_unit.len() > MAX_XTS_SIZE {
-            return Err(XtsError::DataTooLong);
-        }
-        // complete_blocks >= 1
-        let complete_blocks = data_unit.len() / BLOCK_SIZE;
-        // standalone_units >= 0 blocks, suffix = last complete block + possible partial block.
-        let (standalone_blocks, suffix) =
-            data_unit.split_at_mut((complete_blocks - 1) * BLOCK_SIZE);
-        let (last_complete_block, partial_last_block) = suffix.split_at_mut(BLOCK_SIZE);
-        Ok((standalone_blocks, last_complete_block, partial_last_block))
-    }
-
     /// Returns an [XtsTweaked] configured with the specified tweak and a block number of 0.
-    fn tweaked(&self, tweak: Tweak) -> XtsTweaked<A> {
+    fn tweaked(&self, tweak: Tweak) -> XtsDecrypterTweaked<A> {
         let mut bytes = tweak.bytes;
         self.tweak_encryption_cipher.encrypt(&mut bytes);
 
-        XtsTweaked {
+        XtsDecrypterTweaked {
             tweak_state: TweakState::new(bytes),
-            enc_cipher: &self.main_encryption_cipher,
             dec_cipher: &self.main_decryption_cipher,
         }
     }
 }
 
-/// Implementation of XTS-AES-128
-pub struct XtsAes128<C: CryptoProvider>(Xts<C::Aes128>);
-impl<C: CryptoProvider> TweakableBlockCipher<BLOCK_SIZE> for XtsAes128<C> {
+type DataUnitPartsResult<'a> = Result<(&'a mut [u8], &'a mut [u8], &'a mut [u8]), XtsError>;
+
+/// Returns `(standalone blocks, last complete block, partial last block)`.
+fn data_unit_parts(data_unit: &mut [u8]) -> DataUnitPartsResult {
+    if data_unit.len() < BLOCK_SIZE {
+        return Err(XtsError::DataTooShort);
+    } else if data_unit.len() > MAX_XTS_SIZE {
+        return Err(XtsError::DataTooLong);
+    }
+    // complete_blocks >= 1
+    let complete_blocks = data_unit.len() / BLOCK_SIZE;
+    // standalone_units >= 0 blocks, suffix = last complete block + possible partial block.
+    let (standalone_blocks, suffix) = data_unit.split_at_mut((complete_blocks - 1) * BLOCK_SIZE);
+    let (last_complete_block, partial_last_block) = suffix.split_at_mut(BLOCK_SIZE);
+    Ok((standalone_blocks, last_complete_block, partial_last_block))
+}
+
+impl<A: Aes<Key = K::BlockCipherKey>, K: XtsKey + TweakableBlockCipherKey>
+    TweakableBlockCipherEncrypter<BLOCK_SIZE> for XtsEncrypter<A, K>
+{
+    type Key = K;
     type Tweak = Tweak;
 
-    type Key = XtsAes128Key;
-
+    /// Build an [XtsEncrypter] with the provided [Aes] and the provided key.
     fn new(key: &Self::Key) -> Self {
-        Self(build_xts_aes(key))
+        XtsEncrypter {
+            main_encryption_cipher: A::EncryptCipher::new(key.key_1()),
+            tweak_encryption_cipher: A::EncryptCipher::new(key.key_2()),
+            _marker: Default::default(),
+        }
     }
 
     #[allow(clippy::expect_used)]
     fn encrypt(&self, tweak: Self::Tweak, block: &mut [u8; 16]) {
         // we're encrypting precisely one block, so the block number won't advance, and ciphertext
         // stealing will not be applied.
-        self.0
-            .encrypt_data_unit(tweak, block)
-            .expect("One block is a valid size");
-    }
-
-    #[allow(clippy::expect_used)]
-    fn decrypt(&self, tweak: Self::Tweak, block: &mut [u8; 16]) {
-        self.0
-            .decrypt_data_unit(tweak, block)
+        self.encrypt_data_unit(tweak, block)
             .expect("One block is a valid size");
     }
 }
 
-/// Implementation of XTS-AES-256
-pub struct XtsAes256<C: CryptoProvider>(Xts<C::Aes256>);
-impl<C: CryptoProvider> TweakableBlockCipher<BLOCK_SIZE> for XtsAes256<C> {
+impl<A: Aes<Key = K::BlockCipherKey>, K: XtsKey + TweakableBlockCipherKey>
+    TweakableBlockCipherDecrypter<BLOCK_SIZE> for XtsDecrypter<A, K>
+{
+    type Key = K;
     type Tweak = Tweak;
 
-    type Key = XtsAes256Key;
-
-    fn new(key: &Self::Key) -> Self {
-        Self(build_xts_aes(key))
-    }
-
-    #[allow(clippy::expect_used)]
-    fn encrypt(&self, tweak: Self::Tweak, block: &mut [u8; 16]) {
-        // we're encrypting precisely one block, so the block number won't advance, and ciphertext
-        // stealing will not be applied.
-        self.0
-            .encrypt_data_unit(tweak, block)
-            .expect("One block is a valid size");
+    fn new(key: &K) -> Self {
+        XtsDecrypter {
+            main_decryption_cipher: A::DecryptCipher::new(key.key_1()),
+            tweak_encryption_cipher: A::EncryptCipher::new(key.key_2()),
+            _marker: Default::default(),
+        }
     }
 
     #[allow(clippy::expect_used)]
     fn decrypt(&self, tweak: Self::Tweak, block: &mut [u8; 16]) {
-        self.0
-            .decrypt_data_unit(tweak, block)
+        self.decrypt_data_unit(tweak, block)
             .expect("One block is a valid size");
     }
 }
 
-/// XTS spec recommends to not go beyond 2^20 blocks.
-const MAX_XTS_SIZE: usize = (1 << 20) * BLOCK_SIZE;
-
 /// Errors that can occur during XTS encryption/decryption.
 #[derive(Debug, PartialEq, Eq)]
 pub enum XtsError {
@@ -310,6 +324,9 @@
     DataTooLong,
 }
 
+/// XTS spec recommends to not go beyond 2^20 blocks.
+const MAX_XTS_SIZE: usize = (1 << 20) * BLOCK_SIZE;
+
 /// An XTS key comprised of two keys for the underlying block cipher.
 pub trait XtsKey: for<'a> TryFrom<&'a [u8], Error = Self::TryFromError> {
     /// The key used by the block cipher underlying XTS
@@ -576,13 +593,36 @@
 ///
 /// Encryption or decryption is per-block only; ciphertext stealing is not implemented at this
 /// level.
-struct XtsTweaked<'a, A: Aes> {
+struct XtsEncrypterTweaked<'a, A: Aes> {
     tweak_state: TweakState,
     enc_cipher: &'a A::EncryptCipher,
+}
+
+impl<'a, A: Aes> XtsEncrypterTweaked<'a, A> {
+    fn advance_to_next_block_num(&mut self) {
+        self.tweak_state
+            .advance_to_block(self.tweak_state.block_num + 1)
+    }
+
+    /// Encrypt a block in place using the configured tweak and current block number.
+    fn encrypt_block(&self, block: &mut crypto_provider::aes::AesBlock) {
+        array_xor(block, &self.tweak_state.tweak);
+        self.enc_cipher.encrypt(block);
+        array_xor(block, &self.tweak_state.tweak);
+    }
+}
+
+/// An XTS-AES cipher configured with an initial tweak that can be advanced through the block
+/// numbers for that tweak's data unit.
+///
+/// Encryption or decryption is per-block only; ciphertext stealing is not implemented at this
+/// level.
+struct XtsDecrypterTweaked<'a, A: Aes> {
+    tweak_state: TweakState,
     dec_cipher: &'a A::DecryptCipher,
 }
 
-impl<'a, A: Aes> XtsTweaked<'a, A> {
+impl<'a, A: Aes> XtsDecrypterTweaked<'a, A> {
     fn advance_to_next_block_num(&mut self) {
         self.tweak_state
             .advance_to_block(self.tweak_state.block_num + 1)
@@ -597,14 +637,6 @@
     fn set_tweak(&mut self, tweak_state: TweakState) {
         self.tweak_state = tweak_state;
     }
-
-    /// Encrypt a block in place using the configured tweak and current block number.
-    fn encrypt_block(&self, block: &mut crypto_provider::aes::AesBlock) {
-        array_xor(block, &self.tweak_state.tweak);
-        self.enc_cipher.encrypt(block);
-        array_xor(block, &self.tweak_state.tweak);
-    }
-
     fn decrypt_block(&self, block: &mut crypto_provider::aes::AesBlock) {
         // CC = C ^ T
         array_xor(block, &self.tweak_state.tweak);
diff --git a/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs b/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs
index 42f1db4..05eca0d 100644
--- a/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs
+++ b/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs
@@ -17,8 +17,11 @@
 use anyhow::anyhow;
 use crypto_provider::CryptoProvider;
 use crypto_provider_rustcrypto::RustCrypto;
+use ldt_tbc::TweakableBlockCipherDecrypter;
+use ldt_tbc::TweakableBlockCipherEncrypter;
+use ldt_tbc::TweakableBlockCipherKey;
 use std::{collections::hash_map, fs, io, io::BufRead as _};
-use xts_aes::{self, build_xts_aes, XtsAes128Key, XtsAes256Key, XtsKey};
+use xts_aes::{self, XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey};
 
 #[test]
 fn nist_test_vectors_data_unit_seq_128() -> Result<(), anyhow::Error> {
@@ -55,7 +58,7 @@
 
 fn run_test_cases<K, A>(path: &str, expected_num_cases: usize) -> Result<(), anyhow::Error>
 where
-    K: XtsKey,
+    K: XtsKey + TweakableBlockCipherKey,
     A: crypto_provider::aes::Aes<Key = K::BlockCipherKey>,
 {
     let test_cases = parse_test_vector(path)?;
@@ -65,24 +68,32 @@
     for tc in test_cases {
         buf.clear();
 
-        let xts = build_xts_aes::<_, A>(&K::try_from(tc.key.as_slice()).unwrap());
+        let xts_enc = XtsEncrypter::<A, _>::new(&K::try_from(tc.key.as_slice()).unwrap());
+        let xts_dec = XtsDecrypter::<A, _>::new(&K::try_from(tc.key.as_slice()).unwrap());
 
         match tc.test_type {
             TestType::Encrypt => {
                 buf.extend_from_slice(&tc.plaintext);
-                xts.encrypt_data_unit(tc.tweak.clone(), &mut buf).unwrap();
-                assert_eq!(tc.ciphertext, buf, "count {}", tc.count);
+                xts_enc
+                    .encrypt_data_unit(tc.tweak.clone(), &mut buf)
+                    .unwrap();
 
                 // check decryption too just for fun
-                xts.decrypt_data_unit(tc.tweak.clone(), &mut buf).unwrap();
+                xts_dec
+                    .decrypt_data_unit(tc.tweak.clone(), &mut buf)
+                    .unwrap();
                 assert_eq!(tc.plaintext, buf, "count {}", tc.count);
             }
             TestType::Decrypt => {
                 buf.extend_from_slice(&tc.ciphertext);
-                xts.decrypt_data_unit(tc.tweak.clone(), &mut buf).unwrap();
+                xts_dec
+                    .decrypt_data_unit(tc.tweak.clone(), &mut buf)
+                    .unwrap();
                 assert_eq!(tc.plaintext, buf, "count {}", tc.count);
 
-                xts.encrypt_data_unit(tc.tweak.clone(), &mut buf).unwrap();
+                xts_enc
+                    .encrypt_data_unit(tc.tweak.clone(), &mut buf)
+                    .unwrap();
                 assert_eq!(tc.ciphertext, buf, "count {}", tc.count);
             }
         }
diff --git a/nearby/presence/xts_aes/tests/xts_roundtrip.rs b/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs
similarity index 70%
rename from nearby/presence/xts_aes/tests/xts_roundtrip.rs
rename to nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs
index 09bf629..042b62e 100644
--- a/nearby/presence/xts_aes/tests/xts_roundtrip.rs
+++ b/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs
@@ -13,11 +13,15 @@
 // limitations under the License.
 
 use aes::{cipher, cipher::KeyInit as _};
-use crypto_provider::{aes::*, CryptoProvider};
-use crypto_provider_rustcrypto::RustCrypto;
+use alloc::vec::Vec;
+use crypto_provider::aes::*;
+use crypto_provider_rustcrypto::aes::{Aes128, Aes256};
+use ldt_tbc::TweakableBlockCipherDecrypter;
+use ldt_tbc::TweakableBlockCipherEncrypter;
 use rand::{self, distributions, Rng as _};
 use rand_ext::seeded_rng;
-use xts_aes::*;
+use xts_aes::{Tweak, XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey};
+extern crate alloc;
 
 #[test]
 fn roundtrip_self() {
@@ -27,37 +31,40 @@
             let mut key = [0_u8; 32];
             rng.fill(&mut key);
             do_roundtrip(
-                build_xts_aes::<_, <RustCrypto as CryptoProvider>::Aes128>(&XtsAes128Key::from(
-                    &key,
-                )),
+                XtsEncrypter::<Aes128, _>::new(&XtsAes128Key::from(&key)),
+                XtsDecrypter::<Aes128, _>::new(&XtsAes128Key::from(&key)),
                 &mut rng,
             )
         } else {
             let mut key = [0_u8; 64];
             rng.fill(&mut key);
             do_roundtrip(
-                build_xts_aes::<_, <RustCrypto as CryptoProvider>::Aes256>(&XtsAes256Key::from(
-                    &key,
-                )),
+                XtsEncrypter::<Aes256, _>::new(&XtsAes256Key::from(&key)),
+                XtsDecrypter::<Aes256, _>::new(&XtsAes256Key::from(&key)),
                 &mut rng,
             )
         };
     }
 
-    fn do_roundtrip<A: Aes, R: rand::Rng>(xts: Xts<A>, rng: &mut R) {
+    fn do_roundtrip<A: Aes<Key = K::BlockCipherKey>, K: XtsKey, R: rand::Rng>(
+        xts_enc: XtsEncrypter<A, K>,
+        xts_dec: XtsDecrypter<A, K>,
+        rng: &mut R,
+    ) {
         let plaintext_len_range = distributions::Uniform::new_inclusive(BLOCK_SIZE, BLOCK_SIZE * 4);
         let mut plaintext = Vec::<u8>::new();
         plaintext.extend((0..rng.sample(plaintext_len_range)).map(|_| rng.gen::<u8>()));
 
         let mut ciphertext = plaintext.clone();
         let tweak: Tweak = rng.gen::<u128>().into();
-        xts.encrypt_data_unit(tweak.clone(), &mut ciphertext)
+        xts_enc
+            .encrypt_data_unit(tweak.clone(), &mut ciphertext)
             .unwrap();
 
         assert_eq!(plaintext.len(), ciphertext.len());
         assert_ne!(plaintext, ciphertext);
 
-        xts.decrypt_data_unit(tweak, &mut ciphertext).unwrap();
+        xts_dec.decrypt_data_unit(tweak, &mut ciphertext).unwrap();
         assert_eq!(plaintext, ciphertext);
     }
 }
@@ -74,9 +81,8 @@
         if rng.gen() {
             let mut key = [0; 32];
             rng.fill(&mut key);
-            let xts = build_xts_aes::<_, <RustCrypto as CryptoProvider>::Aes128>(
-                &XtsAes128Key::from(&key),
-            );
+            let xts_enc = XtsEncrypter::<Aes128, _>::new(&XtsAes128Key::from(&key));
+            let xts_dec = XtsDecrypter::<Aes128, _>::new(&XtsAes128Key::from(&key));
 
             let primary_cipher =
                 aes::Aes128::new(cipher::generic_array::GenericArray::from_slice(&key[0..16]));
@@ -84,13 +90,12 @@
                 aes::Aes128::new(cipher::generic_array::GenericArray::from_slice(&key[16..]));
             let other_xts = xts_mode::Xts128::new(primary_cipher, tweak_cipher);
 
-            do_roundtrip(xts, other_xts, &mut rng)
+            do_roundtrip(xts_enc, xts_dec, other_xts, &mut rng)
         } else {
             let mut key = [0; 64];
             rng.fill(&mut key);
-            let xts = build_xts_aes::<_, <RustCrypto as CryptoProvider>::Aes256>(
-                &XtsAes256Key::from(&key),
-            );
+            let xts_enc = XtsEncrypter::<Aes256, _>::new(&XtsAes256Key::from(&key));
+            let xts_dec = XtsDecrypter::<Aes256, _>::new(&XtsAes256Key::from(&key));
 
             let primary_cipher =
                 aes::Aes256::new(cipher::generic_array::GenericArray::from_slice(&key[0..32]));
@@ -98,16 +103,18 @@
                 aes::Aes256::new(cipher::generic_array::GenericArray::from_slice(&key[32..]));
             let other_xts = xts_mode::Xts128::new(primary_cipher, tweak_cipher);
 
-            do_roundtrip(xts, other_xts, &mut rng)
+            do_roundtrip(xts_enc, xts_dec, other_xts, &mut rng)
         };
     }
 
     fn do_roundtrip<
-        A: Aes,
+        A: Aes<Key = K::BlockCipherKey>,
+        K: XtsKey,
         C: cipher::BlockEncrypt + cipher::BlockDecrypt + cipher::BlockCipher,
         R: rand::Rng,
     >(
-        xts: Xts<A>,
+        xts_enc: XtsEncrypter<A, K>,
+        xts_dec: XtsDecrypter<A, K>,
         other_xts: xts_mode::Xts128<C>,
         rng: &mut R,
     ) {
@@ -119,7 +126,8 @@
         // encrypt with our impl
         let mut ciphertext = plaintext.clone();
         let tweak: Tweak = rng.gen::<u128>().into();
-        xts.encrypt_data_unit(tweak.clone(), &mut ciphertext)
+        xts_enc
+            .encrypt_data_unit(tweak.clone(), &mut ciphertext)
             .unwrap();
 
         // encrypt with the other impl
@@ -130,7 +138,7 @@
         assert_eq!(ciphertext, other_ciphertext);
 
         // decrypt ciphertext in place
-        xts.decrypt_data_unit(tweak, &mut ciphertext).unwrap();
+        xts_dec.decrypt_data_unit(tweak, &mut ciphertext).unwrap();
         assert_eq!(plaintext, ciphertext);
 
         // and with the other impl
diff --git a/nearby/scripts/build-script.sh b/nearby/scripts/build-script.sh
index f9bbee5..7311df2 100755
--- a/nearby/scripts/build-script.sh
+++ b/nearby/scripts/build-script.sh
@@ -21,27 +21,31 @@
 
 # Use to generate headers for new source code files
 gen_headers() {
+  set -e
   $HOME/go/bin/addlicense -c "Google LLC" -l apache -ignore=**/android/build/** -ignore=target/** -ignore=**/target/** -ignore=".idea/*" -ignore=**/cmake-build/** -ignore="**/java/build/**" .
 }
 
 # Checks the workspace 3rd party crates and makes sure they have a valid license
 check_crate_licenses(){
+    set -e
     cd $SCRIPT_DIR/..
     cargo deny --workspace check
 }
 
 # Checks everything in beto-rust
 check_everything(){
+  set -e
   cd $SCRIPT_DIR/..
   check_license_headers
   check_workspace
-  check_ldt_ffi
   check_boringssl
+  check_ldt_ffi
   build_fuzzers
 }
 
 # Checks everything included in the top level workspace
 check_workspace(){
+  set -e
   cd $SCRIPT_DIR/..
   # ensure formatting is correct (Check for it first because it is fast compared to running tests)
   cargo fmt --check
@@ -59,6 +63,7 @@
 
 # Checks that the license auditing tool is installed and that all source files in the project contain the needed headers
 check_license_headers() {
+  set -e
   cd $SCRIPT_DIR/..
   # install location for those following the default instructions
   ADDLICENSE="$HOME/go/bin/addlicense"
@@ -75,7 +80,15 @@
     exit 1
   fi
 
-  if $ADDLICENSE -check -ignore=**/android/build/** -ignore=target/** -ignore=**/target/** -ignore=".idea/*" -ignore=**/cmake-build/** -ignore="**/java/build/**" .; then
+  if $ADDLICENSE -check \
+      -ignore="**/android/build/**" \
+      -ignore="target/**" \
+      -ignore="**/target/**" \
+      -ignore="**/.idea/**" \
+      -ignore="**/cmake-build/**" \
+      -ignore="**/java/build/**" \
+      -ignore="**/java/*/build/**" \
+      .; then
     echo "License header check succeeded!"
   else
     echo "ERROR: License header missing for above files"
@@ -85,6 +98,7 @@
 
 # Build all fuzz targets
 build_fuzzers() {
+  set -e
   cd $SCRIPT_DIR/..
   # rust fuzzers
   for fuzzed_crate in presence/xts_aes presence/ldt presence/ldt_np_adv connections/ukey2/ukey2_connections; do
@@ -99,19 +113,27 @@
 
 # Builds and runs all tests for all combinations of features for the LDT FFI
 check_ldt_ffi() {
+  set -e
   cd $SCRIPT_DIR/..
   # We need to handle ldt_np_adv_ffi separately since it requires the nightly toolchain
   cd presence/ldt_np_adv_ffi
   cargo fmt --check
   cargo check
+  # Default build, RustCrypto + no_std
   cargo build --release
+  # Turn on std, still using RustCrypto
   cargo build --features=std
-  cargo build --features=openssl
+  # Turn off default features and try to build with std
   cargo build --no-default-features --features=std
+  # Turn off RustCrypto and use openssl
   cargo build --no-default-features --features=openssl
+  # Turn off RustCrypto and use boringssl
+  cargo build --no-default-features --features=boringssl
   cargo doc --no-deps
+  cargo clippy --release
   cargo clippy --features=std
-  cargo clippy --features=openssl
+  cargo clippy --no-default-features --features=openssl
+  cargo clippy --no-default-features --features=boringssl
   cargo clippy --no-default-features --features=std
   cargo deny check
   cd ../
@@ -122,18 +144,28 @@
   make
 
   # test with default build settings (rustcrypto, no_std)
+  echo "Testing default features (no_std + rustcrypto)"
+  (cd ../ldt_np_adv_ffi && cargo build --release)
   (cd ldt_np_c_sample/tests && ctest)
 
-  # test with openssl crypto feature flag
-  (cd ../ldt_np_adv_ffi && cargo build --features openssl --release)
-  (cd ldt_np_c_sample/tests && make && ctest)
-
-  # test with std feature flag
+  # test with std
+  echo "Testing std feature flag"
   (cd ../ldt_np_adv_ffi && cargo build --features std --release)
   (cd ldt_np_c_sample/tests && make && ctest)
 
+  # test with boringssl crypto feature flag
+  echo "Testing boringssl"
+  (cd ../ldt_np_adv_ffi && cargo build --no-default-features --features boringssl --release)
+  (cd ldt_np_c_sample/tests && make && ctest)
+
+  # test with openssl feature flag
+  echo "Testing openssl"
+  (cd ../ldt_np_adv_ffi && cargo build --no-default-features --features openssl --release)
+  (cd ldt_np_c_sample/tests && make && ctest)
+
   # test with std feature flag
-  (cd ../ldt_np_adv_ffi && cargo build --features std --no-default-features --release)
+  echo "Testing std with no default features"
+  (cd ../ldt_np_adv_ffi && cargo build --no-default-features --features std --release)
   (cd ldt_np_c_sample/tests && make && ctest)
   cd ../
 }
@@ -141,6 +173,7 @@
 # Clones boringssl and uses bindgen to generate the rust crate, applies AOSP
 # specific patches to the 3p `openssl` crate so that it can use a bssl backend
 prepare_boringssl() {
+  set -e
   cd $SCRIPT_DIR/../..
   projectroot=$PWD
   mkdir -p boringssl-build && cd boringssl-build
@@ -178,6 +211,7 @@
 # crypto_provider_boringssl is used on Chromium
 # And we want to verify that both of these are tested in our own repo
 check_boringssl() {
+  set -e
   cd $SCRIPT_DIR/../..
   # clones boringssl and uses bindgen to generate the sys bindings
   prepare_boringssl
@@ -197,6 +231,7 @@
 
 # Helper for setting up dependencies on the build machine
 setup_kokoro_macos () {
+  set -e
   go install github.com/google/addlicense@latest
   curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path --default-toolchain 1.68.0
   cargo install --locked cargo-deny --color never 2>&1