Project import generated by Copybara.

GitOrigin-RevId: 06b0c815d958bef0a60978d0766d65af839e37b6
Change-Id: Ifac0c45ae509ca8a8ed793fac5c981d4e23d3bf9
diff --git a/nearby/crypto/crypto_provider/Cargo.toml b/nearby/crypto/crypto_provider/Cargo.toml
index 60f8626..e7dd8ba 100644
--- a/nearby/crypto/crypto_provider/Cargo.toml
+++ b/nearby/crypto/crypto_provider/Cargo.toml
@@ -4,11 +4,14 @@
 edition.workspace = true
 publish.workspace = true
 
+[dependencies]
+tinyvec.workspace = true
+
 [dev-dependencies]
 criterion.workspace = true
 hex-literal.workspace = true
 crypto_provider_openssl.workspace = true
-crypto_provider_rustcrypto.workspace = true
+crypto_provider_rustcrypto = { workspace = true, features = ["std"] }
 rand_ext.workspace = true
 rand.workspace = true
 
@@ -17,6 +20,7 @@
 std = []
 alloc = []
 test_vectors = []
+raw_private_key_permit = []
 
 [[bench]]
 name = "hmac_bench"
diff --git a/nearby/crypto/crypto_provider/src/aead.rs b/nearby/crypto/crypto_provider/src/aead.rs
new file mode 100644
index 0000000..165272e
--- /dev/null
+++ b/nearby/crypto/crypto_provider/src/aead.rs
@@ -0,0 +1,86 @@
+// 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(feature = "alloc")]
+extern crate alloc;
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+
+/// An implementation of AES-GCM-SIV.
+///
+/// An AesGcmSiv impl may be used for encryption and decryption.
+pub trait AesGcmSiv: Aead<Nonce = [u8; 12]> {}
+
+/// An implementation of AES-GCM.
+///
+/// An AesGcm impl may be used for encryption and decryption.
+pub trait AesGcm: Aead<Nonce = [u8; 12]> {}
+
+/// Error returned on unsuccessful AEAD operation.
+#[derive(Debug)]
+pub struct AeadError;
+
+/// Initializes an AEAD
+pub trait AeadInit<K: crate::aes::AesKey> {
+    /// Instantiates a new instance of the AEAD from key material.
+    fn new(key: &K) -> Self;
+}
+
+/// Authenticated Encryption with Associated Data (AEAD) algorithm, where `N` is the size of the
+/// Nonce. Encrypts and decrypts buffers in-place.
+pub trait Aead {
+    /// The size of the authentication tag, this is appended to the message on the encrypt operation
+    /// and truncated from the plaintext after decrypting.
+    const TAG_SIZE: usize;
+
+    /// The cryptographic nonce used by the AEAD. The nonce must be unique for all messages with
+    /// the same key. This is critically important - nonce reuse may completely undermine the
+    /// security of the AEAD. Nonces may be predictable and public, so long as they are unique.
+    type Nonce: AsRef<[u8]>;
+
+    /// The type of the tag, which should always be [u8; Self::TAG_SIZE].
+    type Tag: AsRef<[u8]>;
+
+    /// Encrypt the given buffer containing a plaintext message. On success returns the encrypted
+    /// `msg` and appended auth tag, which will result in a Vec which is  `Self::TAG_SIZE` bytes
+    /// greater than the initial message.
+    #[cfg(feature = "alloc")]
+    fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>;
+
+    /// Encrypt the given buffer containing a plaintext message in-place, and returns the tag in the
+    /// result value.
+    fn encrypt_detached(
+        &self,
+        msg: &mut [u8],
+        aad: &[u8],
+        nonce: &Self::Nonce,
+    ) -> Result<Self::Tag, AeadError>;
+
+    /// Decrypt the message, returning the decrypted plaintext or an error in the event the
+    /// provided authentication tag does not match the given ciphertext. On success the returned
+    /// Vec will only contain the plaintext and so will be `Self::TAG_SIZE` bytes less than the
+    /// initial message.
+    #[cfg(feature = "alloc")]
+    fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>;
+
+    /// Decrypt the message in-place, returning an error and leaving the input `msg` unchanged in
+    /// the event the provided authentication tag does not match the given ciphertext.
+    fn decrypt_detached(
+        &self,
+        msg: &mut [u8],
+        aad: &[u8],
+        nonce: &Self::Nonce,
+        tag: &Self::Tag,
+    ) -> Result<(), AeadError>;
+}
diff --git a/nearby/crypto/crypto_provider/src/aead/aes_gcm_siv.rs b/nearby/crypto/crypto_provider/src/aead/aes_gcm_siv.rs
deleted file mode 100644
index 3be7db3..0000000
--- a/nearby/crypto/crypto_provider/src/aead/aes_gcm_siv.rs
+++ /dev/null
@@ -1,23 +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.
-
-//! Traits for AES-GCM-SIV.
-
-extern crate alloc;
-use crate::aead::Aead;
-
-/// An implementation of AES-GCM-SIV.
-///
-/// An AesGcmSiv impl may be used for encryption and decryption.
-pub trait AesGcmSiv: Aead<Nonce = [u8; 12]> {}
diff --git a/nearby/crypto/crypto_provider/src/aead/mod.rs b/nearby/crypto/crypto_provider/src/aead/mod.rs
deleted file mode 100644
index 27284a9..0000000
--- a/nearby/crypto/crypto_provider/src/aead/mod.rs
+++ /dev/null
@@ -1,50 +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.
-
-extern crate alloc;
-use alloc::vec::Vec;
-
-/// Contains traits for the AES-GCM-SIV AEAD algorithm.
-pub mod aes_gcm_siv;
-
-/// Error returned on unsuccessful AEAD operation.
-pub struct AeadError;
-
-/// Authenticated Encryption with Associated Data (AEAD) algorithm, where `N` is the size of the
-/// Nonce. Encrypts and decrypts buffers in-place.
-pub trait Aead {
-    /// The size of the authentication tag, this is appended to the message on the encrypt operation
-    /// and truncated from the plaintext after decrypting.
-    const TAG_SIZE: usize;
-
-    /// The cryptographic nonce used by the AEAD. The nonce must be unique for all messages with
-    /// the same key. This is critically important - nonce reuse may completely undermine the
-    /// security of the AEAD. Nonces may be predictable and public, so long as they are unique.
-    type Nonce;
-
-    /// The key material used to initialize the AEAD.
-    type Key;
-
-    /// Instantiates a new instance of the AEAD from key material.
-    fn new(key: &Self::Key) -> Self;
-
-    /// Encrypt the given buffer containing a plaintext message in-place. On success increases the
-    /// buffer by `Self::TAG_SIZE` bytes and appends the auth tag to the end of `msg`.
-    fn encrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &Self::Nonce) -> Result<(), AeadError>;
-
-    /// Decrypt the message in-place, returning an error in the event the provided authentication
-    /// tag does not match the given ciphertext. The buffer will be truncated to the length of the
-    /// original plaintext message upon success.
-    fn decrypt(&self, msg: &mut Vec<u8>, aad: &[u8], nonce: &Self::Nonce) -> Result<(), AeadError>;
-}
diff --git a/nearby/crypto/crypto_provider/src/aes/cbc.rs b/nearby/crypto/crypto_provider/src/aes/cbc.rs
index e32c588..59ce52d 100644
--- a/nearby/crypto/crypto_provider/src/aes/cbc.rs
+++ b/nearby/crypto/crypto_provider/src/aes/cbc.rs
@@ -14,7 +14,10 @@
 
 //! Traits for AES-CBC 256 with PKCS7 padding.
 
+#[cfg(feature = "alloc")]
 extern crate alloc;
+use crate::tinyvec::SliceVec;
+#[cfg(feature = "alloc")]
 use alloc::vec::Vec;
 
 use super::Aes256Key;
@@ -24,15 +27,53 @@
 
 /// Trait for implementing AES-CBC with PKCS7 padding.
 pub trait AesCbcPkcs7Padded {
+    /// Calculate the padded output length (e.g. output of `encrypt`) from the unpadded length (e.g.
+    /// input message of `encrypt`).
+    fn padded_output_len(unpadded_len: usize) -> usize {
+        (unpadded_len - (unpadded_len % 16))
+            .checked_add(16)
+            .expect("Padded output length is larger than usize::MAX")
+    }
+
     /// Encrypt message using `key` and `iv`, returning a ciphertext.
+    #[cfg(feature = "alloc")]
     fn encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8>;
+
+    /// Encrypt message using `key` and `iv` in-place in the given `message` vec. The given slice
+    /// vec should have enough capacity to contain both the ciphertext and the padding (which can be
+    /// calculated from `padded_output_len()`). If it doesn't have enough capacity, an error will be
+    /// returned. The contents of the input `message` buffer is undefined in that case.
+    fn encrypt_in_place(
+        key: &Aes256Key,
+        iv: &AesCbcIv,
+        message: &mut SliceVec<u8>,
+    ) -> Result<(), EncryptionError>;
+
     /// Decrypt ciphertext using `key` and `iv`, returning the original message if `Ok()` otherwise
     /// a `DecryptionError` indicating the type of error that occurred while decrypting.
+    #[cfg(feature = "alloc")]
     fn decrypt(
         key: &Aes256Key,
         iv: &AesCbcIv,
         ciphertext: &[u8],
     ) -> Result<Vec<u8>, DecryptionError>;
+
+    /// Decrypt ciphertext using `key` and `iv` and unpad it in-place. Returning the original
+    /// message if `Ok()` otherwise a `DecryptionError` indicating the type of error that occurred
+    /// while decrypting. In that case, the contents of the `ciphertext` buffer is undefined.
+    fn decrypt_in_place(
+        key: &Aes256Key,
+        iv: &AesCbcIv,
+        ciphertext: &mut SliceVec<u8>,
+    ) -> Result<(), DecryptionError>;
+}
+
+/// Error type for describing what went wrong encrypting a message.
+#[derive(Debug, PartialEq, Eq)]
+pub enum EncryptionError {
+    /// Failed to add PKCS7 padding to the output when encrypting a message. This typically happens
+    /// when the given output buffer does not have enough capacity to append the padding.
+    PaddingFailed,
 }
 
 /// Error type for describing what went wrong decrypting a ciphertext.
@@ -43,3 +84,65 @@
     /// correctly. Exposing padding errors can cause a padding oracle vulnerability.
     BadPadding,
 }
+
+#[cfg(test)]
+mod test {
+    #[cfg(feature = "alloc")]
+    extern crate alloc;
+    #[cfg(feature = "alloc")]
+    use alloc::vec::Vec;
+
+    use crate::aes::Aes256Key;
+    use crate::tinyvec::SliceVec;
+
+    use super::{AesCbcIv, AesCbcPkcs7Padded, DecryptionError, EncryptionError};
+
+    #[test]
+    fn test_padded_output_len() {
+        assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(0), 16);
+        assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(15), 16);
+        assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(16), 32);
+        assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(30), 32);
+        assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(32), 48);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_padded_output_len_overflow() {
+        AesCbcPkcs7PaddedStub::padded_output_len(usize::MAX);
+    }
+
+    struct AesCbcPkcs7PaddedStub;
+
+    impl AesCbcPkcs7Padded for AesCbcPkcs7PaddedStub {
+        #[cfg(feature = "alloc")]
+        fn encrypt(_key: &Aes256Key, _iv: &AesCbcIv, _message: &[u8]) -> Vec<u8> {
+            unimplemented!()
+        }
+
+        fn encrypt_in_place(
+            _key: &Aes256Key,
+            _iv: &AesCbcIv,
+            _message: &mut SliceVec<u8>,
+        ) -> Result<(), EncryptionError> {
+            unimplemented!()
+        }
+
+        #[cfg(feature = "alloc")]
+        fn decrypt(
+            _key: &Aes256Key,
+            _iv: &AesCbcIv,
+            _ciphertext: &[u8],
+        ) -> Result<Vec<u8>, DecryptionError> {
+            unimplemented!()
+        }
+
+        fn decrypt_in_place(
+            _key: &Aes256Key,
+            _iv: &AesCbcIv,
+            _ciphertext: &mut SliceVec<u8>,
+        ) -> Result<(), DecryptionError> {
+            unimplemented!()
+        }
+    }
+}
diff --git a/nearby/crypto/crypto_provider/src/aes/ctr.rs b/nearby/crypto/crypto_provider/src/aes/ctr.rs
index 73d4f55..6779fe8 100644
--- a/nearby/crypto/crypto_provider/src/aes/ctr.rs
+++ b/nearby/crypto/crypto_provider/src/aes/ctr.rs
@@ -36,10 +36,8 @@
     /// Build a `Self` from key material.
     fn new(key: &Self::Key, nonce_and_counter: NonceAndCounter) -> Self;
 
-    /// Encrypt the data in place, advancing the counter state appropriately.
-    fn encrypt(&mut self, data: &mut [u8]);
-    /// Decrypt the data in place, advancing the counter state appropriately.
-    fn decrypt(&mut self, data: &mut [u8]);
+    /// Applies the key stream to the data in place, advancing the counter state appropriately.
+    fn apply_keystream(&mut self, data: &mut [u8]);
 }
 
 /// The combined nonce and counter that CTR increments and encrypts to form the keystream.
diff --git a/nearby/crypto/crypto_provider/src/aes/mod.rs b/nearby/crypto/crypto_provider/src/aes/mod.rs
index 83e48de..e359bad 100644
--- a/nearby/crypto/crypto_provider/src/aes/mod.rs
+++ b/nearby/crypto/crypto_provider/src/aes/mod.rs
@@ -20,7 +20,6 @@
 
 pub mod ctr;
 
-#[cfg(feature = "alloc")]
 pub mod cbc;
 
 /// Block size in bytes for AES (and XTS-AES)
diff --git a/nearby/crypto/crypto_provider/src/ed25519.rs b/nearby/crypto/crypto_provider/src/ed25519.rs
index 48c2c50..b435ca2 100644
--- a/nearby/crypto/crypto_provider/src/ed25519.rs
+++ b/nearby/crypto/crypto_provider/src/ed25519.rs
@@ -43,6 +43,59 @@
 /// A byte buffer the size of a ed25519 `PrivateKey`.
 pub type RawPrivateKey = [u8; PRIVATE_KEY_LENGTH];
 
+/// A permission token which may be supplied to methods which allow
+/// converting private keys to/from raw bytes.
+///
+/// In general, operations of this kind should only be done in
+/// development-tools, tests, or in credential storage layers
+/// to prevent accidental exposure of the private key.
+pub struct RawPrivateKeyPermit {
+    _marker: (),
+}
+
+impl RawPrivateKeyPermit {
+    pub(crate) fn new() -> Self {
+        Self { _marker: () }
+    }
+}
+
+#[cfg(feature = "raw_private_key_permit")]
+impl core::default::Default for RawPrivateKeyPermit {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// A crypto-provider-independent representation of the private
+/// key of an ed25519 key-pair, kept in such a way that
+/// it does not permit de-structuring it into raw bytes,
+/// nor constructing one from raw bytes.
+///
+/// Useful for when you want a data-structure to be
+/// crypto-provider independent and contain a private key.
+#[derive(Clone)]
+pub struct PrivateKey {
+    wrapped: RawPrivateKey,
+}
+
+impl PrivateKey {
+    /// Derives the public key corresponding to this private key.
+    pub fn derive_public_key<E: Ed25519Provider>(&self) -> E::PublicKey {
+        let key_pair = E::KeyPair::from_private_key(self);
+        key_pair.public()
+    }
+    /// Returns the raw bytes of this private key.
+    /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+    pub fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey {
+        self.wrapped
+    }
+    /// Constructs a private key from the raw bytes of the key.
+    /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+    pub fn from_raw_private_key(wrapped: RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self {
+        Self { wrapped }
+    }
+}
+
 /// The keypair which includes both public and secret halves of an asymmetric key.
 pub trait KeyPair: Sized {
     /// The ed25519 public key, used when verifying a message
@@ -52,15 +105,37 @@
     type Signature: Signature;
 
     /// Returns the private key bytes of the `KeyPair`.
-    /// This method should only ever be called by code which securely stores private credentials.
-    fn private_key(&self) -> RawPrivateKey;
+    /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+    fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey;
 
     /// Builds a key-pair from a `RawPrivateKey` array of bytes.
-    /// This should only ever be called by code which securely stores private credentials.
-    fn from_private_key(bytes: &RawPrivateKey) -> Self
+    /// This operation is only possible while holding a [`RawPrivateKeyPermit`].
+    fn from_raw_private_key(bytes: &RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self
     where
         Self: Sized;
 
+    /// Returns the private key of the `KeyPair` in an opaque form.
+    fn private_key(&self) -> PrivateKey {
+        // We're okay to reach in and grab the bytes of the private key,
+        // since the way that we're exposing it would require a valid
+        // [`RawPrivateKeyPermit`] to extract them again.
+        let wrapped = self.raw_private_key(&RawPrivateKeyPermit::new());
+        PrivateKey { wrapped }
+    }
+
+    /// Builds a key-pair from a [`PrivateKey`], given in an opaque form.
+    fn from_private_key(private_key: &PrivateKey) -> Self
+    where
+        Self: Sized,
+    {
+        // We're okay to reach in and construct an instance from
+        // the bytes of the private key, since the way that they
+        // were originally expressed would still require a valid
+        // [`RawPrivateKeyPermit`] to access them.
+        let raw_private_key = &private_key.wrapped;
+        Self::from_raw_private_key(raw_private_key, &RawPrivateKeyPermit::new())
+    }
+
     /// Sign the given message and return a digital signature
     fn sign(&self, msg: &[u8]) -> Self::Signature;
 
diff --git a/nearby/crypto/crypto_provider/src/elliptic_curve.rs b/nearby/crypto/crypto_provider/src/elliptic_curve.rs
index d06a21d..d176769 100644
--- a/nearby/crypto/crypto_provider/src/elliptic_curve.rs
+++ b/nearby/crypto/crypto_provider/src/elliptic_curve.rs
@@ -12,12 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-extern crate alloc;
-
 use core::fmt::Debug;
 
-use alloc::vec::Vec;
-
 /// Marker trait for an elliptic curve used for diffie-hellman.
 pub trait Curve {}
 
@@ -42,12 +38,16 @@
     /// The random number generator to be used for generating a secret
     type Rng: crate::CryptoRng;
 
+    /// The for encoded public key bytes, for example a `[u8; N]` array if the size is fixed, or
+    /// `ArrayVec<[u8; N]>` if the size is bounded but not fixed.
+    type EncodedPublicKey: AsRef<[u8]> + Debug;
+
     /// Generates a new random ephemeral secret.
     fn generate_random(rng: &mut Self::Rng) -> Self;
 
     /// Returns the bytes of the public key for this ephemeral secret that is suitable for sending
     /// over the wire for key exchange.
-    fn public_key_bytes(&self) -> Vec<u8>;
+    fn public_key_bytes(&self) -> Self::EncodedPublicKey;
 
     /// Performs diffie-hellman key exchange using this ephemeral secret with the given public key
     /// `other_pub`.
@@ -59,6 +59,8 @@
 
 /// Trait for a public key used for elliptic curve diffie hellman.
 pub trait PublicKey<E: Curve>: Sized + PartialEq + Debug {
+    /// The type for an encoded public key.
+    type EncodedPublicKey: AsRef<[u8]> + Debug;
     /// The error type associated with Public Key.
     type Error: Debug;
 
@@ -71,5 +73,5 @@
     /// the sec1 encoding, may return equivalent but different byte-representations due to point
     /// compression, so it is not necessarily true that `from_bytes(bytes)?.to_bytes() == bytes`
     /// (but it is always true that `from_bytes(key.to_bytes())? == key`).
-    fn to_bytes(&self) -> Vec<u8>;
+    fn to_bytes(&self) -> Self::EncodedPublicKey;
 }
diff --git a/nearby/crypto/crypto_provider/src/lib.rs b/nearby/crypto/crypto_provider/src/lib.rs
index 624072a..0031ebb 100644
--- a/nearby/crypto/crypto_provider/src/lib.rs
+++ b/nearby/crypto/crypto_provider/src/lib.rs
@@ -48,6 +48,8 @@
 /// mod containing traits for ed25519 key generation, signing, and verification
 pub mod ed25519;
 
+pub use tinyvec;
+
 /// 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
@@ -80,10 +82,13 @@
     /// using SHA-512 (SHA-2) and Curve25519
     type Ed25519: ed25519::Ed25519Provider;
     /// The trait defining AES-128-GCM-SIV, a nonce-misuse resistant AEAD with a key size of 16 bytes.
-    type Aes128GcmSiv: aead::aes_gcm_siv::AesGcmSiv<Key = Aes128Key>;
+    type Aes128GcmSiv: aead::AesGcmSiv + aead::AeadInit<Aes128Key>;
     /// The trait defining AES-256-GCM-SIV, a nonce-misuse resistant AEAD with a key size of 32 bytes.
-    type Aes256GcmSiv: aead::aes_gcm_siv::AesGcmSiv<Key = Aes256Key>;
-
+    type Aes256GcmSiv: aead::AesGcmSiv + aead::AeadInit<Aes256Key>;
+    /// The trait defining AES-128-GCM, an AEAD with a key size of 16 bytes.
+    type Aes128Gcm: aead::AesGcm + aead::AeadInit<Aes128Key>;
+    /// The trait defining AES-256-GCM, an AEAD with a key size of 32 bytes.
+    type Aes256Gcm: aead::AesGcm + aead::AeadInit<Aes256Key>;
     /// The cryptographically secure random number generator
     type CryptoRng: CryptoRng;
 
diff --git a/nearby/crypto/crypto_provider/src/p256.rs b/nearby/crypto/crypto_provider/src/p256.rs
index 90d3542..fd7b531 100644
--- a/nearby/crypto/crypto_provider/src/p256.rs
+++ b/nearby/crypto/crypto_provider/src/p256.rs
@@ -12,10 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-extern crate alloc;
+use tinyvec::ArrayVec;
 
 use crate::elliptic_curve::{Curve, EcdhProvider, PublicKey};
-use alloc::vec::Vec;
 use core::fmt::Debug;
 
 /// Marker type for P256 implementation. This is used by EcdhProvider as its type parameter.
@@ -23,6 +22,24 @@
 pub enum P256 {}
 impl Curve for P256 {}
 
+/// Longest length for a sec-1 encoded P256 public key, which is the uncompressed format
+/// `04 || X || Y` as defined in section 2.3.3 of the SECG SEC 1 ("Elliptic Curve Cryptography")
+/// standard.
+const P256_PUBLIC_KEY_MAX_LENGTH: usize = 65;
+
+/// Whether an elliptic curve point should be compressed or not.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PointCompression {
+    /// The elliptic curve point should be compressed (`02 || X` or `03 || X`),
+    /// as defined in section 2.3.3 of the SECG SEC 1 ("Elliptic Curve
+    /// Cryptography").
+    Compressed,
+    /// The elliptic curve point should be uncompressed (`04 || X || Y`), as
+    /// defined in section 2.3.3 of the SECG SEC 1 ("Elliptic Curve
+    /// Cryptography").
+    Uncompressed,
+}
+
 /// Trait for a NIST-P256 public key.
 pub trait P256PublicKey: Sized + PartialEq + Debug {
     /// The error type associated with this implementation.
@@ -36,7 +53,10 @@
     /// ("Elliptic Curve Cryptography") standard. Note that it is not necessarily true that
     /// `from_sec1_bytes(bytes)?.to_sec1_bytes() == bytes` because of point compression. (But it is
     /// always true that `from_sec1_bytes(key.to_sec1_bytes())? == key`).
-    fn to_sec1_bytes(&self) -> Vec<u8>;
+    fn to_sec1_bytes(
+        &self,
+        point_compression: PointCompression,
+    ) -> ArrayVec<[u8; P256_PUBLIC_KEY_MAX_LENGTH]>;
 
     /// Converts this public key's x and y coordinates on the elliptic curve to big endian octet
     /// strings.
@@ -48,13 +68,14 @@
 
 impl<P: P256PublicKey> PublicKey<P256> for P {
     type Error = <Self as P256PublicKey>::Error;
+    type EncodedPublicKey = ArrayVec<[u8; P256_PUBLIC_KEY_MAX_LENGTH]>;
 
     fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
         Self::from_sec1_bytes(bytes)
     }
 
-    fn to_bytes(&self) -> Vec<u8> {
-        Self::to_sec1_bytes(self)
+    fn to_bytes(&self) -> Self::EncodedPublicKey {
+        Self::to_sec1_bytes(self, PointCompression::Uncompressed)
     }
 }