Project import generated by Copybara.

GitOrigin-RevId: 8e45d682af0c4329d479cb7a1e0b83d70c9a94f3
Change-Id: I81aa3256a4bd578d47e2743b4e67c74cb24823f9
diff --git a/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
new file mode 100644
index 0000000..ad5a4b8
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
@@ -0,0 +1,37 @@
+[package]
+name = "crypto_provider_rustcrypto"
+version.workspace = true
+edition.workspace = true
+publish.workspace = true
+
+[dependencies]
+aead = "0.5.1"
+aes-gcm-siv = { version = "0.11.1", features = ["aes"], optional = true }
+crypto_provider.workspace = true
+hmac.workspace = true
+hkdf.workspace = true
+sha2.workspace = true
+x25519-dalek.workspace = true
+p256 = { workspace = true, features = ["ecdh"], default-features = false }
+sec1.workspace = true
+ed25519-dalek = { workspace = true, default-features = false }
+rand = { workspace = true, default-features = false }
+rand_core_05_adapter.workspace = true
+rand_core.workspace = true
+subtle.workspace = true
+aes.workspace = true
+ctr.workspace = true
+cbc.workspace = true
+cfg-if.workspace = true
+rand_chacha = { workspace = true, default-features = false, optional = true }
+
+[dev-dependencies]
+hex.workspace = true
+crypto_provider = { workspace = true, features = ["testing"] }
+crypto_provider_rustcrypto = { path = ".", features = ["std"] }
+
+[features]
+default = ["alloc", "gcm_siv", "rand_chacha"]
+std = ["ed25519-dalek/default", "rand/std", "rand/std_rng", "crypto_provider/std", "crypto_provider/alloc"]
+alloc = ["aead/bytes"]
+gcm_siv = ["crypto_provider/gcm_siv", "dep:aes-gcm-siv"]
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aes/cbc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aes/cbc.rs
new file mode 100644
index 0000000..b43876c
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aes/cbc.rs
@@ -0,0 +1,53 @@
+// 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.
+
+extern crate alloc;
+use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
+use aes::Aes256;
+use alloc::vec::Vec;
+use crypto_provider::aes::{
+    cbc::{AesCbcIv, DecryptionError},
+    Aes256Key, AesKey,
+};
+
+/// RustCrypto implementation of AES-CBC with PKCS7 padding
+pub enum AesCbcPkcs7Padded {}
+impl crypto_provider::aes::cbc::AesCbcPkcs7Padded for AesCbcPkcs7Padded {
+    fn encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8> {
+        let encryptor = cbc::Encryptor::<Aes256>::new(key.as_array().into(), iv.into());
+        encryptor.encrypt_padded_vec_mut::<Pkcs7>(message)
+    }
+
+    fn decrypt(
+        key: &Aes256Key,
+        iv: &AesCbcIv,
+        ciphertext: &[u8],
+    ) -> Result<Vec<u8>, DecryptionError> {
+        cbc::Decryptor::<Aes256>::new(key.as_array().into(), iv.into())
+            .decrypt_padded_vec_mut::<Pkcs7>(ciphertext)
+            .map_err(|_| DecryptionError::BadPadding)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::AesCbcPkcs7Padded;
+    use core::marker::PhantomData;
+    use crypto_provider::aes::cbc::testing::*;
+
+    #[apply(aes_256_cbc_test_cases)]
+    fn aes_256_cbc_test(testcase: CryptoProviderTestCase<AesCbcPkcs7Padded>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aes/gcm_siv.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aes/gcm_siv.rs
new file mode 100644
index 0000000..d5c655b
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aes/gcm_siv.rs
@@ -0,0 +1,102 @@
+// 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 aes_gcm_siv::{AeadInPlace, Aes128GcmSiv, Aes256GcmSiv, KeyInit, Nonce};
+
+use crypto_provider::aes::gcm_siv::{bytes, GcmSivError};
+use crypto_provider::aes::{Aes128Key, Aes256Key, AesKey};
+
+pub struct AesGcmSiv128(Aes128GcmSiv);
+
+impl crypto_provider::aes::gcm_siv::AesGcmSiv for AesGcmSiv128 {
+    type Key = Aes128Key;
+
+    fn new(key: &Self::Key) -> Self {
+        Self(Aes128GcmSiv::new(key.as_slice().into()))
+    }
+
+    fn encrypt(
+        &self,
+        data: &mut bytes::BytesMut,
+        aad: &[u8],
+        nonce: &[u8],
+    ) -> Result<(), GcmSivError> {
+        self.0
+            .encrypt_in_place(Nonce::from_slice(nonce), aad, data)
+            .map_err(|_| GcmSivError::EncryptOutBufferTooSmall)
+    }
+
+    fn decrypt(
+        &self,
+        data: &mut bytes::BytesMut,
+        aad: &[u8],
+        nonce: &[u8],
+    ) -> Result<(), GcmSivError> {
+        self.0
+            .decrypt_in_place(Nonce::from_slice(nonce), aad, data)
+            .map_err(|_| GcmSivError::DecryptTagDoesNotMatch)
+    }
+}
+
+pub struct AesGcmSiv256(Aes256GcmSiv);
+
+impl crypto_provider::aes::gcm_siv::AesGcmSiv for AesGcmSiv256 {
+    type Key = Aes256Key;
+
+    fn new(key: &Self::Key) -> Self {
+        Self(Aes256GcmSiv::new(key.as_slice().into()))
+    }
+
+    fn encrypt(
+        &self,
+        data: &mut bytes::BytesMut,
+        aad: &[u8],
+        nonce: &[u8],
+    ) -> Result<(), GcmSivError> {
+        self.0
+            .encrypt_in_place(Nonce::from_slice(nonce), aad, data)
+            .map_err(|_| GcmSivError::EncryptOutBufferTooSmall)
+    }
+
+    fn decrypt(
+        &self,
+        data: &mut bytes::BytesMut,
+        aad: &[u8],
+        nonce: &[u8],
+    ) -> Result<(), GcmSivError> {
+        self.0
+            .decrypt_in_place(Nonce::from_slice(nonce), aad, data)
+            .map_err(|_| GcmSivError::DecryptTagDoesNotMatch)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use core::marker::PhantomData;
+
+    use crypto_provider::aes::gcm_siv::testing::*;
+    use crypto_provider::aes::testing::*;
+
+    use super::*;
+
+    #[apply(aes_128_gcm_siv_test_cases)]
+    fn aes_gcm_siv_128_test(testcase: CryptoProviderTestCase<AesGcmSiv128>) {
+        testcase(PhantomData);
+    }
+
+    #[apply(aes_256_gcm_siv_test_cases)]
+    fn aes_gcm_siv_256_test(testcase: CryptoProviderTestCase<AesGcmSiv256>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/aes/mod.rs b/nearby/crypto/crypto_provider_rustcrypto/src/aes/mod.rs
new file mode 100644
index 0000000..a351b81
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/aes/mod.rs
@@ -0,0 +1,191 @@
+// 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.
+
+//! Implementation of `crypto_provider::aes` types using RustCrypto's `aes`.
+#![forbid(unsafe_code)]
+
+use aes::cipher::{
+    generic_array, BlockDecrypt as _, BlockEncrypt as _, KeyInit as _, KeyIvInit as _,
+    StreamCipher as _,
+};
+
+use crypto_provider::aes::{
+    Aes, Aes128Key, Aes256Key, AesBlock, AesCipher, AesDecryptCipher, AesEncryptCipher, AesKey,
+};
+
+/// Module implementing AES-CBC.
+#[cfg(feature = "alloc")]
+pub(crate) mod cbc;
+#[cfg(feature = "gcm_siv")]
+pub(crate) mod gcm_siv;
+
+/// Rust crypto implementation of AES-128
+pub struct Aes128;
+impl Aes for Aes128 {
+    type Key = Aes128Key;
+    type EncryptCipher = Aes128Cipher;
+    type DecryptCipher = Aes128Cipher;
+}
+
+/// Rust crypto implementation of AES-256
+pub struct Aes256;
+impl Aes for Aes256 {
+    type Key = Aes256Key;
+    type EncryptCipher = Aes256Cipher;
+    type DecryptCipher = Aes256Cipher;
+}
+
+/// A Rust Crypto AES-128 cipher used for encryption and decryption
+pub struct Aes128Cipher(aes::Aes128);
+
+impl AesCipher for Aes128Cipher {
+    type Key = Aes128Key;
+
+    fn new(key: &Self::Key) -> Self {
+        Self(aes::Aes128::new(key.as_array().into()))
+    }
+}
+
+impl AesEncryptCipher for Aes128Cipher {
+    fn encrypt(&self, block: &mut AesBlock) {
+        self.0
+            .encrypt_block(generic_array::GenericArray::from_mut_slice(
+                block.as_mut_slice(),
+            ));
+    }
+}
+
+impl AesDecryptCipher for Aes128Cipher {
+    fn decrypt(&self, block: &mut AesBlock) {
+        self.0
+            .decrypt_block(generic_array::GenericArray::from_mut_slice(
+                block.as_mut_slice(),
+            ))
+    }
+}
+
+/// A Rust Crypto AES-256 cipher used for encryption and decryption
+pub struct Aes256Cipher(aes::Aes256);
+
+impl AesCipher for Aes256Cipher {
+    type Key = Aes256Key;
+
+    fn new(key: &Self::Key) -> Self {
+        Self(aes::Aes256::new(key.as_array().into()))
+    }
+}
+
+impl AesEncryptCipher for Aes256Cipher {
+    fn encrypt(&self, block: &mut AesBlock) {
+        self.0
+            .encrypt_block(generic_array::GenericArray::from_mut_slice(
+                block.as_mut_slice(),
+            ));
+    }
+}
+
+impl AesDecryptCipher for Aes256Cipher {
+    fn decrypt(&self, block: &mut AesBlock) {
+        self.0
+            .decrypt_block(generic_array::GenericArray::from_mut_slice(
+                block.as_mut_slice(),
+            ))
+    }
+}
+
+/// RustCrypto implementation of AES-CTR 128.
+pub struct AesCtr128 {
+    cipher: ctr::Ctr128BE<aes::Aes128>,
+}
+
+impl crypto_provider::aes::ctr::AesCtr for AesCtr128 {
+    type Key = crypto_provider::aes::Aes128Key;
+
+    fn new(key: &Self::Key, iv: [u8; 16]) -> Self {
+        Self {
+            cipher: ctr::Ctr128BE::new(key.as_array().into(), &iv.into()),
+        }
+    }
+
+    fn encrypt(&mut self, data: &mut [u8]) {
+        self.cipher.apply_keystream(data);
+    }
+
+    fn decrypt(&mut self, data: &mut [u8]) {
+        self.cipher.apply_keystream(data);
+    }
+}
+
+/// RustCrypto implementation of AES-CTR 256.
+pub struct AesCtr256 {
+    cipher: ctr::Ctr128BE<aes::Aes256>,
+}
+
+impl crypto_provider::aes::ctr::AesCtr for AesCtr256 {
+    type Key = crypto_provider::aes::Aes256Key;
+
+    fn new(key: &Self::Key, iv: [u8; 16]) -> Self {
+        Self {
+            cipher: ctr::Ctr128BE::new(key.as_array().into(), &iv.into()),
+        }
+    }
+
+    fn encrypt(&mut self, data: &mut [u8]) {
+        self.cipher.apply_keystream(data);
+    }
+
+    fn decrypt(&mut self, data: &mut [u8]) {
+        self.cipher.apply_keystream(data);
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use core::marker::PhantomData;
+
+    use crypto_provider::aes::ctr::testing::*;
+    use crypto_provider::aes::testing::*;
+
+    use super::*;
+
+    #[apply(aes_128_ctr_test_cases)]
+    fn aes_128_ctr_test(testcase: CryptoProviderTestCase<AesCtr128>) {
+        testcase(PhantomData);
+    }
+
+    #[apply(aes_256_ctr_test_cases)]
+    fn aes_256_ctr_test(testcase: CryptoProviderTestCase<AesCtr256>) {
+        testcase(PhantomData);
+    }
+
+    #[apply(aes_128_encrypt_test_cases)]
+    fn aes_128_encrypt_test(testcase: CryptoProviderTestCase<Aes128Cipher>) {
+        testcase(PhantomData);
+    }
+
+    #[apply(aes_128_decrypt_test_cases)]
+    fn aes_128_decrypt_test(testcase: CryptoProviderTestCase<Aes128Cipher>) {
+        testcase(PhantomData);
+    }
+
+    #[apply(aes_256_encrypt_test_cases)]
+    fn aes_256_encrypt_test(testcase: CryptoProviderTestCase<Aes256Cipher>) {
+        testcase(PhantomData);
+    }
+
+    #[apply(aes_256_decrypt_test_cases)]
+    fn aes_256_decrypt_test(testcase: CryptoProviderTestCase<Aes256Cipher>) {
+        testcase(PhantomData);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
new file mode 100644
index 0000000..874aa82
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
@@ -0,0 +1,122 @@
+// 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::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);
+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()
+    }
+
+    fn from_bytes(bytes: [u8; KEY_PAIR_LENGTH]) -> Result<Self, InvalidBytes> {
+        ed25519_dalek::Keypair::from_bytes(&bytes)
+            .map(Self)
+            .map_err(|_| InvalidBytes)
+    }
+
+    #[allow(clippy::expect_used)]
+    fn sign(&self, msg: &[u8]) -> Self::Signature {
+        Self::Signature::from_bytes(&self.0.sign(msg).to_bytes())
+            .expect("a signature will always produce valid bytes for creating a Signature")
+    }
+
+    //TODO: allow providing a crypto rng and make it a no-op for openssl if the need arises to
+    // improve perf of keypair generation
+    #[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),
+        ))
+    }
+
+    fn public(&self) -> Self::PublicKey {
+        PublicKey(self.0.public)
+    }
+}
+
+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)
+            .map(Self)
+            .map_err(|_| InvalidSignature)
+    }
+
+    fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
+        self.0.to_bytes()
+    }
+}
+
+pub struct PublicKey(ed25519_dalek::PublicKey);
+impl crypto_provider::ed25519::PublicKey for PublicKey {
+    type Signature = Signature;
+
+    fn from_bytes(bytes: [u8; KEY_LENGTH]) -> Result<Self, InvalidBytes>
+    where
+        Self: Sized,
+    {
+        ed25519_dalek::PublicKey::from_bytes(&bytes)
+            .map(PublicKey)
+            .map_err(|_| InvalidBytes)
+    }
+
+    fn to_bytes(&self) -> [u8; KEY_LENGTH] {
+        self.0.to_bytes()
+    }
+
+    fn verify_strict(
+        &self,
+        message: &[u8],
+        signature: &Self::Signature,
+    ) -> Result<(), SignatureError> {
+        self.0
+            .verify_strict(message, &signature.0)
+            .map_err(|_| SignatureError)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::ed25519::Ed25519;
+    use crypto_provider::ed25519::testing::{run_rfc_test_vectors, run_wycheproof_test_vectors};
+
+    #[test]
+    fn wycheproof_test_ed25519_rustcrypto() {
+        run_wycheproof_test_vectors::<Ed25519>()
+    }
+
+    #[test]
+    fn rfc_test_ed25519_rustcrypto() {
+        run_rfc_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
new file mode 100644
index 0000000..d6ca687
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/hkdf_rc.rs
@@ -0,0 +1,74 @@
+// 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::hkdf::InvalidLength;
+use hmac::digest::block_buffer::Eager;
+use hmac::digest::consts::U256;
+use hmac::digest::core_api::{
+    BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, UpdateCore,
+};
+use hmac::digest::typenum::{IsLess, Le, NonZero};
+use hmac::digest::{HashMarker, OutputSizeUser};
+
+/// RustCrypto based hkdf implementation
+#[derive(Clone)]
+pub struct Hkdf<D>
+where
+    D: OutputSizeUser,
+    D: CoreProxy,
+    D::Core: HashMarker
+        + UpdateCore
+        + FixedOutputCore
+        + BufferKindUser<BufferKind = Eager>
+        + Default
+        + Clone,
+    <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
+    Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
+{
+    hkdf_impl: hkdf::Hkdf<D>,
+}
+
+impl<D> crypto_provider::hkdf::Hkdf for Hkdf<D>
+where
+    D: OutputSizeUser,
+    D: CoreProxy,
+    D::Core: HashMarker
+        + UpdateCore
+        + FixedOutputCore
+        + BufferKindUser<BufferKind = Eager>
+        + Default
+        + Clone,
+    <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
+    Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
+{
+    fn new(salt: Option<&[u8]>, ikm: &[u8]) -> Self {
+        Hkdf {
+            hkdf_impl: hkdf::Hkdf::new(salt, ikm),
+        }
+    }
+
+    fn expand_multi_info(
+        &self,
+        info_components: &[&[u8]],
+        okm: &mut [u8],
+    ) -> Result<(), InvalidLength> {
+        self.hkdf_impl
+            .expand_multi_info(info_components, okm)
+            .map_err(|_| InvalidLength)
+    }
+
+    fn expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength> {
+        self.hkdf_impl.expand(info, okm).map_err(|_| InvalidLength)
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs
new file mode 100644
index 0000000..e31b815
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/hmac_rc.rs
@@ -0,0 +1,114 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crypto_provider::hmac::{InvalidLength, MacError};
+use hmac::digest::block_buffer::Eager;
+use hmac::digest::consts::U256;
+use hmac::digest::core_api::{
+    BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, UpdateCore,
+};
+use hmac::digest::typenum::{IsLess, Le, NonZero};
+use hmac::digest::{HashMarker, OutputSizeUser};
+use hmac::Mac;
+
+/// RustCrypto based hmac implementation
+pub struct Hmac<D>
+where
+    D: OutputSizeUser,
+    D: CoreProxy,
+    D::Core: HashMarker
+        + UpdateCore
+        + FixedOutputCore
+        + BufferKindUser<BufferKind = Eager>
+        + Default
+        + Clone,
+    <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
+    Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
+{
+    hmac_impl: hmac::Hmac<D>,
+}
+
+impl crypto_provider::hmac::Hmac<32> for Hmac<sha2::Sha256> {
+    #[allow(clippy::expect_used)]
+    fn new_from_key(key: [u8; 32]) -> Self {
+        hmac::Hmac::new_from_slice(&key)
+            .map(|hmac| Self { hmac_impl: hmac })
+            .expect("length will always be valid because input key is of fixed size")
+    }
+
+    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
+        hmac::Hmac::new_from_slice(key)
+            .map(|hmac| Self { hmac_impl: hmac })
+            .map_err(|_| InvalidLength)
+    }
+
+    fn update(&mut self, data: &[u8]) {
+        self.hmac_impl.update(data);
+    }
+
+    fn finalize(self) -> [u8; 32] {
+        self.hmac_impl.finalize().into_bytes().into()
+    }
+
+    fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> {
+        self.hmac_impl.verify_slice(tag).map_err(|_| MacError)
+    }
+
+    fn verify(self, tag: [u8; 32]) -> Result<(), MacError> {
+        self.hmac_impl.verify(&tag.into()).map_err(|_| MacError)
+    }
+
+    fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> {
+        self.hmac_impl
+            .verify_truncated_left(tag)
+            .map_err(|_| MacError)
+    }
+}
+
+impl crypto_provider::hmac::Hmac<64> for Hmac<sha2::Sha512> {
+    #[allow(clippy::expect_used)]
+    fn new_from_key(key: [u8; 64]) -> Self {
+        hmac::Hmac::new_from_slice(&key)
+            .map(|hmac| Self { hmac_impl: hmac })
+            .expect("length will always be valid because input key is of fixed size")
+    }
+
+    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
+        hmac::Hmac::new_from_slice(key)
+            .map(|hmac| Self { hmac_impl: hmac })
+            .map_err(|_| InvalidLength)
+    }
+
+    fn update(&mut self, data: &[u8]) {
+        self.hmac_impl.update(data);
+    }
+
+    fn finalize(self) -> [u8; 64] {
+        self.hmac_impl.finalize().into_bytes().into()
+    }
+
+    fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> {
+        self.hmac_impl.verify_slice(tag).map_err(|_| MacError)
+    }
+
+    fn verify(self, tag: [u8; 64]) -> Result<(), MacError> {
+        self.hmac_impl.verify(&tag.into()).map_err(|_| MacError)
+    }
+
+    fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> {
+        self.hmac_impl
+            .verify_truncated_left(tag)
+            .map_err(|_| MacError)
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
new file mode 100644
index 0000000..9807f81
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
@@ -0,0 +1,127 @@
+// 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.
+#![no_std]
+#![forbid(unsafe_code)]
+#![deny(
+    missing_docs,
+    clippy::indexing_slicing,
+    clippy::unwrap_used,
+    clippy::panic,
+    clippy::expect_used
+)]
+
+//! Crate which provides impls for CryptoProvider backed by RustCrypto crates
+
+/// Contains the RustCrypto backed AES impl for CryptoProvider
+pub mod aes;
+/// Contains the RustCrypto backed impl for ed25519 key generation, signing, and verification
+mod ed25519;
+/// Contains the RustCrypto backed hkdf impl for CryptoProvider
+mod hkdf_rc;
+/// Contains the RustCrypto backed hmac impl for CryptoProvider
+mod hmac_rc;
+/// Contains the RustCrypto backed P256 impl for CryptoProvider
+mod p256;
+/// Contains the RustCrypto backed SHA2 impl for CryptoProvider
+mod sha2_rc;
+/// Contains the RustCrypto backed X25519 impl for CryptoProvider
+mod x25519;
+
+pub use hkdf;
+pub use hmac;
+
+use cfg_if::cfg_if;
+use core::{fmt::Debug, marker::PhantomData};
+use rand::{RngCore, SeedableRng};
+use rand_core::CryptoRng;
+use subtle::ConstantTimeEq;
+
+cfg_if! {
+    if #[cfg(feature = "std")] {
+        /// Providing a type alias for compatibility with existing usage of RustCrypto
+        /// by default we use StdRng for the underlying csprng
+        pub type RustCrypto = RustCryptoImpl<rand::rngs::StdRng>;
+    } else {
+        /// A no_std compatible implementation of CryptoProvider backed by RustCrypto crates
+        pub type RustCrypto = RustCryptoImpl<rand_chacha::ChaCha20Rng>;
+    }
+}
+
+/// The the RustCrypto backed struct which implements CryptoProvider
+#[derive(Default, Clone, Debug, PartialEq, Eq)]
+pub struct RustCryptoImpl<R: CryptoRng + SeedableRng + RngCore> {
+    _marker: PhantomData<R>,
+}
+
+impl<R: CryptoRng + SeedableRng + RngCore> RustCryptoImpl<R> {
+    ///
+    pub fn new() -> Self {
+        Self {
+            _marker: Default::default(),
+        }
+    }
+}
+
+impl<R: CryptoRng + SeedableRng + RngCore + Eq + PartialEq + Debug + Clone + Send>
+    crypto_provider::CryptoProvider for RustCryptoImpl<R>
+{
+    type HkdfSha256 = hkdf_rc::Hkdf<sha2::Sha256>;
+    type HmacSha256 = hmac_rc::Hmac<sha2::Sha256>;
+    type HkdfSha512 = hkdf_rc::Hkdf<sha2::Sha512>;
+    type HmacSha512 = hmac_rc::Hmac<sha2::Sha512>;
+    #[cfg(feature = "alloc")]
+    type AesCbcPkcs7Padded = aes::cbc::AesCbcPkcs7Padded;
+    type X25519 = x25519::X25519Ecdh<R>;
+    type P256 = p256::P256Ecdh<R>;
+    type Sha256 = sha2_rc::RustCryptoSha256;
+    type Sha512 = sha2_rc::RustCryptoSha512;
+    type Aes128 = aes::Aes128;
+    type Aes256 = aes::Aes256;
+    type AesCtr128 = aes::AesCtr128;
+    type AesCtr256 = aes::AesCtr256;
+    type Ed25519 = ed25519::Ed25519;
+    type CryptoRng = RcRng<R>;
+
+    fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
+        a.ct_eq(b).into()
+    }
+}
+
+/// A RustCrypto wrapper for RNG
+pub struct RcRng<R>(R);
+
+impl<R: rand_core::CryptoRng + RngCore + SeedableRng> crypto_provider::CryptoRng for RcRng<R> {
+    fn new() -> Self {
+        Self(R::from_entropy())
+    }
+
+    fn next_u64(&mut self) -> u64 {
+        self.0.next_u64()
+    }
+}
+
+#[cfg(test)]
+mod testing;
+
+#[cfg(test)]
+mod tests {
+    use crate::RustCrypto;
+    use core::marker::PhantomData;
+    use crypto_provider::sha2::testing::*;
+
+    #[apply(sha2_test_cases)]
+    fn sha2_tests(testcase: CryptoProviderTestCase<RustCrypto>) {
+        testcase(PhantomData::<RustCrypto>);
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/p256.rs b/nearby/crypto/crypto_provider_rustcrypto/src/p256.rs
new file mode 100644
index 0000000..a50bec8
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/p256.rs
@@ -0,0 +1,149 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+extern crate alloc;
+
+use crate::RcRng;
+use alloc::vec::Vec;
+use core::marker::PhantomData;
+use crypto_provider::{
+    elliptic_curve::{EcdhProvider, EphemeralSecret},
+    p256::P256,
+};
+use p256::{
+    elliptic_curve,
+    elliptic_curve::{
+        generic_array::GenericArray,
+        sec1::{FromEncodedPoint, ToEncodedPoint},
+    },
+};
+use rand::{RngCore, SeedableRng};
+use rand_core::CryptoRng;
+
+/// Implementation of NIST-P256 using RustCrypto crates.
+pub struct P256Ecdh<R> {
+    _marker: PhantomData<R>,
+}
+
+impl<R: CryptoRng + SeedableRng + RngCore + Send> EcdhProvider<P256> for P256Ecdh<R> {
+    type PublicKey = P256PublicKey;
+    type EphemeralSecret = P256EphemeralSecret<R>;
+    type SharedSecret = [u8; 32];
+}
+
+/// A NIST-P256 public key.
+#[derive(Debug, PartialEq, Eq)]
+pub struct P256PublicKey(p256::PublicKey);
+impl crypto_provider::p256::P256PublicKey for P256PublicKey {
+    type Error = elliptic_curve::Error;
+
+    fn from_sec1_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
+        p256::PublicKey::from_sec1_bytes(bytes).map(Self)
+    }
+
+    fn to_sec1_bytes(&self) -> Vec<u8> {
+        self.0.to_encoded_point(true).as_bytes().to_vec()
+    }
+
+    #[allow(clippy::expect_used)]
+    fn to_affine_coordinates(&self) -> Result<([u8; 32], [u8; 32]), Self::Error> {
+        let p256_key = self.0.to_encoded_point(false);
+        let x: &[u8; 32] = p256_key
+            .x()
+            .expect("Generated key should not be on identity point")
+            .as_ref();
+        let y: &[u8; 32] = p256_key
+            .y()
+            .expect("Generated key should not be on identity point")
+            .as_ref();
+        Ok((*x, *y))
+    }
+    fn from_affine_coordinates(x: &[u8; 32], y: &[u8; 32]) -> Result<Self, Self::Error> {
+        let key_option: Option<p256::PublicKey> =
+            p256::PublicKey::from_encoded_point(&p256::EncodedPoint::from_affine_coordinates(
+                &GenericArray::clone_from_slice(x),
+                &GenericArray::clone_from_slice(y),
+                false,
+            ))
+            .into();
+        key_option.map(Self).ok_or(elliptic_curve::Error)
+    }
+}
+
+/// Ephemeral secrect for use in a P256 Diffie-Hellman
+pub struct P256EphemeralSecret<R: CryptoRng + SeedableRng + RngCore> {
+    secret: p256::ecdh::EphemeralSecret,
+    _marker: PhantomData<R>,
+}
+
+impl<R: CryptoRng + SeedableRng + RngCore + Send> EphemeralSecret<P256> for P256EphemeralSecret<R> {
+    type Impl = P256Ecdh<R>;
+    type Error = sec1::Error;
+    type Rng = RcRng<R>;
+
+    fn generate_random(rng: &mut Self::Rng) -> Self {
+        Self {
+            secret: p256::ecdh::EphemeralSecret::random(&mut rng.0),
+            _marker: Default::default(),
+        }
+    }
+
+    fn public_key_bytes(&self) -> Vec<u8> {
+        self.secret
+            .public_key()
+            .to_encoded_point(false)
+            .as_bytes()
+            .into()
+    }
+
+    fn diffie_hellman(
+        self,
+        other_pub: &P256PublicKey,
+    ) -> Result<<Self::Impl as EcdhProvider<P256>>::SharedSecret, Self::Error> {
+        let shared_secret = p256::ecdh::EphemeralSecret::diffie_hellman(&self.secret, &other_pub.0);
+        let bytes: <Self::Impl as EcdhProvider<P256>>::SharedSecret =
+            (*shared_secret.raw_secret_bytes()).into();
+        Ok(bytes)
+    }
+}
+
+#[cfg(test)]
+impl<R: CryptoRng + SeedableRng + RngCore + Send>
+    crypto_provider::elliptic_curve::EphemeralSecretForTesting<P256> for P256EphemeralSecret<R>
+{
+    fn from_private_components(
+        private_bytes: &[u8; 32],
+        _public_key: &P256PublicKey,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            secret: p256::ecdh::EphemeralSecret::random(&mut crate::testing::MockCryptoRng {
+                values: private_bytes.iter(),
+            }),
+            _marker: Default::default(),
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::P256Ecdh;
+    use core::marker::PhantomData;
+    use crypto_provider::p256::testing::*;
+    use rand::rngs::StdRng;
+
+    #[apply(p256_test_cases)]
+    fn p256_tests(testcase: CryptoProviderTestCase<P256Ecdh<StdRng>>) {
+        testcase(PhantomData::<P256Ecdh<StdRng>>)
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/sha2_rc.rs b/nearby/crypto/crypto_provider_rustcrypto/src/sha2_rc.rs
new file mode 100644
index 0000000..977eb83
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/sha2_rc.rs
@@ -0,0 +1,37 @@
+// 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 sha2::Digest;
+
+/// RustCrypto implementation for SHA256
+pub struct RustCryptoSha256;
+
+impl crypto_provider::sha2::Sha256 for RustCryptoSha256 {
+    fn sha256(input: &[u8]) -> [u8; 32] {
+        let mut digest = sha2::Sha256::new();
+        digest.update(input);
+        digest.finalize().into()
+    }
+}
+
+/// RustCrypto implementation for SHA512
+pub struct RustCryptoSha512;
+
+impl crypto_provider::sha2::Sha512 for RustCryptoSha512 {
+    fn sha512(input: &[u8]) -> [u8; 64] {
+        let mut digest = sha2::Sha512::new();
+        digest.update(input);
+        digest.finalize().into()
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/testing.rs b/nearby/crypto/crypto_provider_rustcrypto/src/testing.rs
new file mode 100644
index 0000000..f606492
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/testing.rs
@@ -0,0 +1,51 @@
+#![allow(clippy::expect_used)]
+// 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.
+
+#[cfg(test)]
+/// A mock implementation of a CryptoRng that returns the given bytes in `values` in
+/// sequence.
+pub(crate) struct MockCryptoRng<'a, I: Iterator<Item = &'a u8>> {
+    pub(crate) values: I,
+}
+
+impl<'a, I: Iterator<Item = &'a u8>> rand::CryptoRng for MockCryptoRng<'a, I> {}
+
+impl<'a, I: Iterator<Item = &'a u8>> rand::RngCore for MockCryptoRng<'a, I> {
+    fn fill_bytes(&mut self, dest: &mut [u8]) {
+        for i in dest {
+            *i = *self
+                .values
+                .next()
+                .expect("Expecting more data in MockCryptoRng input");
+        }
+    }
+
+    fn next_u32(&mut self) -> u32 {
+        let mut bytes = [0; 4];
+        self.fill_bytes(&mut bytes);
+        u32::from_le_bytes(bytes)
+    }
+
+    fn next_u64(&mut self) -> u64 {
+        let mut bytes = [0; 8];
+        self.fill_bytes(&mut bytes);
+        u64::from_le_bytes(bytes)
+    }
+
+    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
+        self.fill_bytes(dest);
+        Ok(())
+    }
+}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs b/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
new file mode 100644
index 0000000..a184d44
--- /dev/null
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/x25519.rs
@@ -0,0 +1,122 @@
+// 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.
+
+extern crate alloc;
+
+use crate::RcRng;
+use alloc::vec::Vec;
+use core::marker::PhantomData;
+use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey};
+use crypto_provider::x25519::X25519;
+use rand::RngCore;
+use rand_core::{CryptoRng, SeedableRng};
+
+/// The RustCrypto implementation of X25519 ECDH.
+pub struct X25519Ecdh<R> {
+    _marker: PhantomData<R>,
+}
+
+impl<R: CryptoRng + RngCore + SeedableRng + Send> EcdhProvider<X25519> for X25519Ecdh<R> {
+    type PublicKey = X25519PublicKey;
+    type EphemeralSecret = X25519EphemeralSecret<R>;
+    type SharedSecret = [u8; 32];
+}
+
+/// A X25519 ephemeral secret used for Diffie-Hellman.
+pub struct X25519EphemeralSecret<R: CryptoRng + RngCore + SeedableRng> {
+    secret: x25519_dalek::EphemeralSecret,
+    marker: PhantomData<R>,
+}
+
+impl<R: CryptoRng + RngCore + SeedableRng + Send> EphemeralSecret<X25519>
+    for X25519EphemeralSecret<R>
+{
+    type Impl = X25519Ecdh<R>;
+    type Error = Error;
+    type Rng = RcRng<R>;
+
+    fn generate_random(rng: &mut Self::Rng) -> Self {
+        Self {
+            secret: x25519_dalek::EphemeralSecret::new(&mut rng.0),
+            marker: Default::default(),
+        }
+    }
+
+    fn public_key_bytes(&self) -> Vec<u8> {
+        let pubkey: x25519_dalek::PublicKey = (&self.secret).into();
+        pubkey.to_bytes().into()
+    }
+
+    fn diffie_hellman(
+        self,
+        other_pub: &<X25519Ecdh<R> as EcdhProvider<X25519>>::PublicKey,
+    ) -> Result<<X25519Ecdh<R> as EcdhProvider<X25519>>::SharedSecret, Self::Error> {
+        Ok(x25519_dalek::EphemeralSecret::diffie_hellman(self.secret, &other_pub.0).to_bytes())
+    }
+}
+
+#[cfg(test)]
+impl<R: CryptoRng + RngCore + SeedableRng + Send>
+    crypto_provider::elliptic_curve::EphemeralSecretForTesting<X25519>
+    for X25519EphemeralSecret<R>
+{
+    fn from_private_components(
+        private_bytes: &[u8; 32],
+        _public_key: &X25519PublicKey,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            secret: x25519_dalek::EphemeralSecret::new(&mut crate::testing::MockCryptoRng {
+                values: private_bytes.iter(),
+            }),
+            marker: Default::default(),
+        })
+    }
+}
+
+/// A X25519 public key.
+#[derive(Debug, PartialEq, Eq)]
+pub struct X25519PublicKey(x25519_dalek::PublicKey);
+
+impl PublicKey<X25519> for X25519PublicKey {
+    type Error = Error;
+
+    fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
+        let byte_sized: [u8; 32] = bytes.try_into().map_err(|_| Error::WrongSize)?;
+        Ok(Self(byte_sized.into()))
+    }
+
+    fn to_bytes(&self) -> Vec<u8> {
+        self.0.as_bytes().to_vec()
+    }
+}
+
+/// Error type for the RustCrypto implementation of x25519.
+#[derive(Debug)]
+pub enum Error {
+    /// Unexpected size for the given input.
+    WrongSize,
+}
+
+#[cfg(test)]
+mod tests {
+    use super::X25519Ecdh;
+    use core::marker::PhantomData;
+    use crypto_provider::x25519::testing::*;
+    use rand::rngs::StdRng;
+
+    #[apply(x25519_test_cases)]
+    fn x25519_tests(testcase: CryptoProviderTestCase<X25519Ecdh<StdRng>>) {
+        testcase(PhantomData::<X25519Ecdh<StdRng>>)
+    }
+}