Project import generated by Copybara.
GitOrigin-RevId: 89e6b51eb1f772d98e85f45fc0d5c7fe23230c16
Change-Id: Icf50d4604bba16d6925221eb14132e6e8057dac8
diff --git a/nearby/.gitignore b/nearby/.gitignore
index b7d2235..49cb45e 100644
--- a/nearby/.gitignore
+++ b/nearby/.gitignore
@@ -3,3 +3,4 @@
/*.mdb
/auth_token.txt
.DS_Store
+presence/cmake-build-debug
diff --git a/nearby/Cargo.lock b/nearby/Cargo.lock
index 657ac34..dd4f6ff 100644
--- a/nearby/Cargo.lock
+++ b/nearby/Cargo.lock
@@ -780,17 +780,6 @@
]
[[package]]
-name = "derive-getters"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0122f262bf9c9a367829da84f808d9fb128c10ef283bbe7b0922a77cf07b2747"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1138,12 +1127,6 @@
]
[[package]]
-name = "init_with"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0175f63815ce00183bf755155ad0cb48c65226c5d17a724e369c25418d2b7699"
-
-[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1386,7 +1369,6 @@
"crypto_provider",
"crypto_provider_default",
"hex",
- "init_with",
"lazy_static",
"ldt",
"ldt_np_adv",
@@ -1407,6 +1389,17 @@
]
[[package]]
+name = "np_adv_dynamic"
+version = "0.1.0"
+dependencies = [
+ "array_view",
+ "crypto_provider",
+ "np_adv",
+ "sink",
+ "thiserror",
+]
+
+[[package]]
name = "np_ed25519"
version = "0.1.0"
dependencies = [
@@ -1425,8 +1418,10 @@
"crypto_provider_default",
"handle_map",
"lazy_static",
+ "ldt_np_adv",
"lock_adapter",
"np_adv",
+ "np_hkdf",
]
[[package]]
@@ -2307,7 +2302,6 @@
dependencies = [
"crypto_provider",
"crypto_provider_default",
- "derive-getters",
"log",
"num-bigint",
"rand",
diff --git a/nearby/Cargo.toml b/nearby/Cargo.toml
index df92f64..774e1d8 100644
--- a/nearby/Cargo.toml
+++ b/nearby/Cargo.toml
@@ -20,6 +20,7 @@
"presence/ldt_np_jni",
"presence/ldt_tbc",
"presence/np_adv",
+ "presence/np_adv_dynamic",
"presence/np_ed25519",
"presence/np_ffi_core",
"presence/np_hkdf",
@@ -40,6 +41,22 @@
"presence/np_c_ffi",
]
+[workspace.lints.rust]
+unsafe_code = "deny"
+missing_docs = "deny"
+trivial_casts = "deny"
+trivial_numeric_casts = "deny"
+unused_extern_crates = "deny"
+unused_import_braces = "deny"
+unused_results = "deny"
+
+[workspace.lints.clippy]
+indexing_slicing = "deny"
+unwrap_used = "deny"
+panic = "deny"
+expect_used = "deny"
+
+
[workspace.dependencies]
# local crates
array_ref = { path = "presence/array_ref" }
@@ -63,6 +80,7 @@
ldt_np_adv = { path = "presence/ldt_np_adv" }
ldt_tbc = { path = "presence/ldt_tbc" }
np_adv = { path = "presence/np_adv" }
+np_adv_dynamic = { path = "presence/np_adv_dynamic" }
np_ed25519 = { path = "presence/np_ed25519" }
np_ffi_core = { path = "presence/np_ffi_core" }
sink = { path = "presence/sink" }
@@ -122,6 +140,7 @@
strum = { version = "0.25.0", default-features=false }
strum_macros = { version = "0.25.3", default-features=false }
owo-colors = "3.5.0"
+rhai = { version = "1.16.3", features = ["sync"] }
[workspace.package]
version = "0.1.0"
diff --git a/nearby/connections/connections_adv/connections_adv/Cargo.toml b/nearby/connections/connections_adv/connections_adv/Cargo.toml
index ff17ad2..2b0710d 100644
--- a/nearby/connections/connections_adv/connections_adv/Cargo.toml
+++ b/nearby/connections/connections_adv/connections_adv/Cargo.toml
@@ -4,6 +4,5 @@
edition.workspace = true
publish.workspace = true
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
+[lints]
+workspace = true
\ No newline at end of file
diff --git a/nearby/connections/connections_adv/connections_adv/src/lib.rs b/nearby/connections/connections_adv/connections_adv/src/lib.rs
index 4f7198b..4cfcdfa 100644
--- a/nearby/connections/connections_adv/connections_adv/src/lib.rs
+++ b/nearby/connections/connections_adv/connections_adv/src/lib.rs
@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//! Placeholder crate for connections advertisements
+
+/// placeholder
pub fn add(left: usize, right: usize) -> usize {
left + right
}
diff --git a/nearby/connections/ukey2/ukey2/Cargo.toml b/nearby/connections/ukey2/ukey2/Cargo.toml
index afae71e..161c5b4 100644
--- a/nearby/connections/ukey2/ukey2/Cargo.toml
+++ b/nearby/connections/ukey2/ukey2/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
test_rustcrypto = ["crypto_provider_default/rustcrypto"]
@@ -16,7 +19,6 @@
ukey2_proto.workspace = true
log.workspace = true
-derive-getters = "0.2.0"
num-bigint = "0.4.3"
[dev-dependencies]
diff --git a/nearby/connections/ukey2/ukey2/src/lib.rs b/nearby/connections/ukey2/ukey2/src/lib.rs
index d8f2270..dc17b83 100644
--- a/nearby/connections/ukey2/ukey2/src/lib.rs
+++ b/nearby/connections/ukey2/ukey2/src/lib.rs
@@ -18,15 +18,6 @@
//! establish a secure channel.
//!
//! For a full description of the protocol, see <https://github.com/google/ukey2>.
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- trivial_casts,
- trivial_numeric_casts,
- unused_extern_crates,
- unused_import_braces,
- unused_results
-)]
mod proto_adapter;
mod state_machine;
diff --git a/nearby/connections/ukey2/ukey2/src/proto_adapter.rs b/nearby/connections/ukey2/ukey2/src/proto_adapter.rs
index de3c4b9..2986276 100644
--- a/nearby/connections/ukey2/ukey2/src/proto_adapter.rs
+++ b/nearby/connections/ukey2/ukey2/src/proto_adapter.rs
@@ -17,7 +17,6 @@
use crypto_provider::elliptic_curve::EcdhProvider;
use crypto_provider::p256::{P256EcdhProvider, P256PublicKey, P256};
use crypto_provider::CryptoProvider;
-use derive_getters::Getters;
use ukey2_proto::ukey2_all_proto::{securemessage, ukey};
/// For generated proto types for UKEY2 messages
@@ -79,23 +78,44 @@
ClientFinish,
}
-#[derive(Getters)]
pub(crate) struct ClientInit {
version: i32,
commitments: Vec<CipherCommitment>,
next_protocol: String,
}
+impl ClientInit {
+ pub fn version(&self) -> i32 {
+ self.version
+ }
+
+ pub fn commitments(&self) -> &[CipherCommitment] {
+ &self.commitments
+ }
+
+ pub fn next_protocol(&self) -> &str {
+ &self.next_protocol
+ }
+}
+
#[allow(dead_code)]
-#[derive(Getters)]
pub(crate) struct ServerInit {
version: i32,
random: [u8; 32],
handshake_cipher: HandshakeCipher,
- #[getter(skip)]
pub(crate) public_key: Vec<u8>,
}
+impl ServerInit {
+ pub fn version(&self) -> i32 {
+ self.version
+ }
+
+ pub fn handshake_cipher(&self) -> HandshakeCipher {
+ self.handshake_cipher
+ }
+}
+
pub(crate) struct ClientFinished {
pub(crate) public_key: Vec<u8>,
}
@@ -119,12 +139,22 @@
}
}
-#[derive(Clone, Getters)]
+#[derive(Clone)]
pub(crate) struct CipherCommitment {
cipher: HandshakeCipher,
commitment: Vec<u8>,
}
+impl CipherCommitment {
+ pub fn cipher(&self) -> HandshakeCipher {
+ self.cipher
+ }
+
+ pub fn commitment(&self) -> &[u8] {
+ &self.commitment
+ }
+}
+
pub(crate) enum GenericPublicKey<C: CryptoProvider> {
Ec256(<C::P256 as EcdhProvider<P256>>::PublicKey),
// Other public key types are not supported
@@ -256,6 +286,7 @@
/// representation. If the input byte array is not positive or cannot be fit into 32 byte unsigned
/// int range, then `None` is returned.
fn positive_twos_complement_to_32_byte_unsigned(twos_complement: &[u8]) -> Option<[u8; 32]> {
+ #[allow(clippy::indexing_slicing)]
if !twos_complement.is_empty() && (twos_complement[0] & 0x80) == 0 {
let mut twos_complement_iter = twos_complement.iter().rev();
let mut result = [0_u8; 32];
diff --git a/nearby/connections/ukey2/ukey2/src/state_machine.rs b/nearby/connections/ukey2/ukey2/src/state_machine.rs
index c7cefc3..d2021e6 100644
--- a/nearby/connections/ukey2/ukey2/src/state_machine.rs
+++ b/nearby/connections/ukey2/ukey2/src/state_machine.rs
@@ -43,7 +43,8 @@
error_message: self.msg,
..Default::default()
};
- alert_message.to_wrapped_msg().write_to_bytes().unwrap()
+ #[allow(clippy::expect_used)]
+ alert_message.to_wrapped_msg().write_to_bytes().expect("Writing to proto should succeed")
}
}
diff --git a/nearby/connections/ukey2/ukey2/src/tests.rs b/nearby/connections/ukey2/ukey2/src/tests.rs
index 65274a6..92c0358 100644
--- a/nearby/connections/ukey2/ukey2/src/tests.rs
+++ b/nearby/connections/ukey2/ukey2/src/tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use crate::{
proto_adapter::{IntoAdapter as _, MessageType, ToWrappedMessage as _},
ukey2_handshake::HandshakeCipher,
diff --git a/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs b/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs
index 70db4a3..0b2be0e 100644
--- a/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs
+++ b/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs
@@ -12,6 +12,9 @@
// 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.
+#![allow(clippy::expect_used)]
+// TODO: remove this and convert all unwraps to expects
+#![allow(clippy::unwrap_used)]
pub(crate) use crate::proto_adapter::{
CipherCommitment, ClientFinished, ClientInit, GenericPublicKey, HandshakeCipher,
@@ -89,7 +92,7 @@
HandshakeCipher::P256Sha512 => {
let p256_key =
<C::P256 as P256EcdhProvider>::PublicKey::from_bytes(key.as_slice())
- .unwrap();
+ .expect("");
let (x, y) = p256_key.to_affine_coordinates().unwrap();
let bigboi_x = num_bigint::BigInt::from_biguint(
num_bigint::Sign::Plus,
@@ -167,7 +170,7 @@
client_init: ClientInit,
client_init_msg_bytes: Vec<u8>,
) -> Result<Ukey2ServerStage2<C>, ClientInitError> {
- if client_init.version() != &1 {
+ if client_init.version() != 1 {
return Err(ClientInitError::BadVersion);
}
@@ -188,7 +191,7 @@
// proto enum uses the priority as the numeric value
.max_by_key(|c| c.cipher().as_proto() as i32)
.ok_or(ClientInitError::BadHandshakeCipher)?;
- match *commitment.cipher() {
+ match commitment.cipher() {
// pick in priority order
HandshakeCipher::Curve25519Sha512 => {
let secret = ServerKeyPair::Curve25519(
@@ -474,7 +477,7 @@
server_init: ServerInit,
server_init_bytes: Vec<u8>,
) -> Result<Ukey2Client, ServerInitError> {
- if server_init.version() != &1 {
+ if server_init.version() != 1 {
return Err(ServerInitError::BadVersion);
}
@@ -483,7 +486,7 @@
.commitment_ciphers
.iter()
.fold(None, |accum, c| {
- if server_init.handshake_cipher() == c {
+ if server_init.handshake_cipher() == *c {
match accum {
None => Some(c),
Some(_) => accum,
diff --git a/nearby/connections/ukey2/ukey2/tests/tests.rs b/nearby/connections/ukey2/ukey2/tests/tests.rs
index 2f51a8c..85b972c 100644
--- a/nearby/connections/ukey2/ukey2/tests/tests.rs
+++ b/nearby/connections/ukey2/ukey2/tests/tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use crypto_provider_default::CryptoProviderImpl;
use rand::{rngs::StdRng, SeedableRng};
use std::collections::hash_set;
diff --git a/nearby/connections/ukey2/ukey2_connections/Cargo.toml b/nearby/connections/ukey2/ukey2_connections/Cargo.toml
index 8337e96..e7884c4 100644
--- a/nearby/connections/ukey2/ukey2_connections/Cargo.toml
+++ b/nearby/connections/ukey2/ukey2_connections/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
test_boringssl = ["crypto_provider_default/boringssl"]
diff --git a/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs b/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs
index e48400a..f816165 100644
--- a/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs
+++ b/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(missing_docs, clippy::expect_used, clippy::unwrap_used)]
+
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use rand::{Rng, SeedableRng};
@@ -65,10 +67,10 @@
let (mut initiator_ctx, mut server_ctx) =
run_handshake_with_rng::<CryptoProviderImpl, _>(rand::rngs::StdRng::from_entropy());
for len in [10 * kib, 1024 * kib] {
- group.throughput(Throughput::Bytes(len as u64));
+ let _ = group.throughput(Throughput::Bytes(len as u64));
plaintext.resize(len, 0);
rand::thread_rng().fill(&mut plaintext[..]);
- group.bench_function(format!("UKEY2 encrypt/decrypt {}KiB", len / kib), |b| {
+ let _ = group.bench_function(format!("UKEY2 encrypt/decrypt {}KiB", len / kib), |b| {
b.iter(|| {
let msg = initiator_ctx
.encode_message_to_peer::<CryptoProviderImpl, &[u8]>(&plaintext, None);
diff --git a/nearby/connections/ukey2/ukey2_connections/src/lib.rs b/nearby/connections/ukey2/ukey2_connections/src/lib.rs
index 3a441bb..b3ed937 100644
--- a/nearby/connections/ukey2/ukey2_connections/src/lib.rs
+++ b/nearby/connections/ukey2/ukey2_connections/src/lib.rs
@@ -24,7 +24,9 @@
//! from the handshake context once the handshake is complete, and controls the encryption and
//! decryption of the payload messages.
-#![deny(missing_docs)]
+#![allow(clippy::expect_used)]
+//TODO: remove this and fix instances of unwrap
+#![allow(clippy::unwrap_used, clippy::panic)]
mod crypto_utils;
mod d2d_connection_context_v1;
diff --git a/nearby/connections/ukey2/ukey2_connections/src/tests.rs b/nearby/connections/ukey2/ukey2_connections/src/tests.rs
index 32a6b28..d6acecc 100644
--- a/nearby/connections/ukey2/ukey2_connections/src/tests.rs
+++ b/nearby/connections/ukey2/ukey2_connections/src/tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::indexing_slicing)]
+
use crypto_provider::CryptoProvider;
use crypto_provider_default::CryptoProviderImpl;
use rand::SeedableRng;
diff --git a/nearby/connections/ukey2/ukey2_jni/Cargo.toml b/nearby/connections/ukey2/ukey2_jni/Cargo.toml
index 4852444..08566dd 100644
--- a/nearby/connections/ukey2/ukey2_jni/Cargo.toml
+++ b/nearby/connections/ukey2/ukey2_jni/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
diff --git a/nearby/connections/ukey2/ukey2_jni/src/lib.rs b/nearby/connections/ukey2/ukey2_jni/src/lib.rs
index 82d317e..b7764fa 100644
--- a/nearby/connections/ukey2/ukey2_jni/src/lib.rs
+++ b/nearby/connections/ukey2/ukey2_jni/src/lib.rs
@@ -12,6 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//! JNI bindings for the ukey2 rust implementation
+
+#![allow(unsafe_code, clippy::expect_used)]
+//TODO: remove this and fix instances of unwrap/panic
+#![allow(clippy::unwrap_used, clippy::panic)]
+
use std::collections::HashMap;
use jni::objects::{JByteArray, JClass};
@@ -52,14 +58,28 @@
}
pub(crate) fn insert_handshake_handle(item: D2DBox) -> u64 {
- let handle = generate_handle();
- HANDLE_MAPPING.lock().insert(handle, item);
+ let mut handle = generate_handle();
+ let map = HANDLE_MAPPING.lock();
+ while map.contains_key(&handle) {
+ handle = generate_handle();
+ }
+
+ let result = HANDLE_MAPPING.lock().insert(handle, item);
+ // result should always be None since we checked that handle map does not contain the key already
+ assert!(result.is_none());
handle
}
pub(crate) fn insert_conn_handle(item: ConnectionBox) -> u64 {
- let handle = generate_handle();
- CONNECTION_HANDLE_MAPPING.lock().insert(handle, item);
+ let mut handle = generate_handle();
+ let map = CONNECTION_HANDLE_MAPPING.lock();
+ while map.contains_key(&handle) {
+ handle = generate_handle();
+ }
+
+ let result = CONNECTION_HANDLE_MAPPING.lock().insert(handle, item);
+ // result should always be None since we checked that handle map does not contain the key already
+ assert!(result.is_none());
handle
}
@@ -71,7 +91,8 @@
HandshakeError(HandshakeError),
}
-// D2DHandshakeContext
+/// Tells the caller whether the handshake has completed or not. If the handshake is complete,
+/// the caller may call `to_connection_context`to obtain a connection context.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DHandshakeContext_is_1handshake_1complete(
mut env: JNIEnv,
@@ -88,6 +109,7 @@
is_complete as jboolean
}
+/// Creates a new handshake context
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DHandshakeContext_create_1context(
_: JNIEnv,
@@ -107,6 +129,7 @@
}
}
+/// Constructs the next message that should be sent in the handshake.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DHandshakeContext_get_1next_1handshake_1message(
mut env: JNIEnv,
@@ -130,9 +153,10 @@
.into_raw()
}
-#[no_mangle]
+/// Parses a handshake message and advances the internal state of the context.
+// Safety: We know the message pointer is safe as it is coming directly from the JVM.
#[allow(clippy::not_unsafe_ptr_arg_deref)]
-/// Safety: We know the message pointer is safe as it is coming directly from the JVM.
+#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DHandshakeContext_parse_1handshake_1message(
mut env: JNIEnv,
_: JClass,
@@ -163,6 +187,8 @@
}
}
+/// Returns the `CompletedHandshake` using the results from this handshake context. May only
+/// be called if `is_handshake_complete` returns true.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DHandshakeContext_get_1verification_1string(
mut env: JNIEnv,
@@ -201,6 +227,8 @@
.into_raw()
}
+/// Creates a [`D2DConnectionContextV1`] using the results of the handshake. May only be called
+/// if `is_handshake_complete` returns true.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DHandshakeContext_to_1connection_1context(
mut env: JNIEnv,
@@ -224,16 +252,17 @@
.expect("failed to find error class");
return -1;
} else {
- HANDLE_MAPPING.lock().remove(&(context_handle as u64));
+ let _ = HANDLE_MAPPING.lock().remove(&(context_handle as u64));
}
insert_conn_handle(Box::new(conn_context.unwrap())) as jlong
}
-// D2DConnectionContextV1
-#[no_mangle]
+/// Once initiator and responder have exchanged public keys, use this method to encrypt and
+/// sign a payload. Both initiator and responder devices can use this message.
+// Safety: We know the payload and associated_data pointers are safe as they are coming directly
+// from the JVM.
#[allow(clippy::not_unsafe_ptr_arg_deref)]
-/// Safety: We know the payload and associated_data pointers are safe as they are coming directly
-/// from the JVM.
+#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DConnectionContextV1_encode_1message_1to_1peer(
mut env: JNIEnv,
_: JClass,
@@ -271,10 +300,13 @@
.into_raw()
}
-#[no_mangle]
+/// Once `InitiatorHello` and `ResponderHello` (and payload) are exchanged, use this method to
+/// decrypt and verify a message received from the other device. Both initiator and responder
+/// devices can use this message.
+// Safety: We know the message and associated_data pointers are safe as they are coming directly
+// from the JVM.
#[allow(clippy::not_unsafe_ptr_arg_deref)]
-/// Safety: We know the message and associated_data pointers are safe as they are coming directly
-/// from the JVM.
+#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DConnectionContextV1_decode_1message_1from_1peer(
mut env: JNIEnv,
_: JClass,
@@ -322,6 +354,7 @@
.into_raw()
}
+/// Returns the last sequence number used to encode a message.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DConnectionContextV1_get_1sequence_1number_1for_1encoding(
mut env: JNIEnv,
@@ -329,14 +362,15 @@
context_handle: jlong,
) -> jint {
if let Some(ctx) = CONNECTION_HANDLE_MAPPING.lock().get(&(context_handle as u64)) {
- ctx.get_sequence_number_for_encoding() as jint
+ ctx.get_sequence_number_for_encoding()
} else {
env.throw_new("com/google/security/cryptauth/lib/securegcm/BadHandleException", "")
.expect("failed to find error class");
- -1 as jint
+ -1
}
}
+/// Returns the last sequence number used to decode a message.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DConnectionContextV1_get_1sequence_1number_1for_1decoding(
mut env: JNIEnv,
@@ -344,14 +378,16 @@
context_handle: jlong,
) -> jint {
if let Some(ctx) = CONNECTION_HANDLE_MAPPING.lock().get(&(context_handle as u64)) {
- ctx.get_sequence_number_for_decoding() as jint
+ ctx.get_sequence_number_for_decoding()
} else {
env.throw_new("com/google/security/cryptauth/lib/securegcm/BadHandleException", "")
.expect("failed to find error class");
- -1 as jint
+ -1
}
}
+/// Creates a saved session that can later be used for resumption. The session data may be
+/// persisted, but it must be stored in a secure location.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DConnectionContextV1_save_1session(
mut env: JNIEnv,
@@ -369,9 +405,10 @@
.into_raw()
}
+/// Creates a connection context from a saved session.
+// Safety: We know the session_info pointer is safe because it is coming directly from the JVM.
#[no_mangle]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
-/// Safety: We know the session_info pointer is safe because it is coming directly from the JVM.
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DConnectionContextV1_from_1saved_1session(
mut env: JNIEnv,
_: JClass,
@@ -399,6 +436,9 @@
insert_conn_handle(conn_context_final) as jlong
}
+/// Returns a cryptographic digest (SHA256) of the session keys prepended by the SHA256 hash
+/// of the ASCII string "D2D". Since the server and client share the same session keys, the
+/// resulting session unique is also the same.
#[no_mangle]
pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_D2DConnectionContextV1_get_1session_1unique(
mut env: JNIEnv,
diff --git a/nearby/connections/ukey2/ukey2_shell/Cargo.toml b/nearby/connections/ukey2/ukey2_shell/Cargo.toml
index d1f48e4..9a2856d 100644
--- a/nearby/connections/ukey2/ukey2_shell/Cargo.toml
+++ b/nearby/connections/ukey2/ukey2_shell/Cargo.toml
@@ -4,11 +4,11 @@
edition.workspace = true
publish.workspace = true
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[lints]
+workspace = true
[dependencies]
crypto_provider_rustcrypto = { workspace = true, features = [ "alloc" ] }
ukey2_rs = { version = "0.1.0", path = "../ukey2" }
ukey2_connections = { version = "0.1.0", path = "../ukey2_connections" }
-
clap = { version = "4.0.17", default-features = false, features = ["std", "derive"] }
diff --git a/nearby/connections/ukey2/ukey2_shell/src/main.rs b/nearby/connections/ukey2/ukey2_shell/src/main.rs
index e4bcc0d..3eca7b0 100644
--- a/nearby/connections/ukey2/ukey2_shell/src/main.rs
+++ b/nearby/connections/ukey2/ukey2_shell/src/main.rs
@@ -12,6 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//! Provides a sample ukey2 shell app which can be run from the command line
+
+#![allow(clippy::expect_used)]
+//TODO: remove this and fix instances of unwrap
+#![allow(clippy::unwrap_used, clippy::panic, clippy::indexing_slicing)]
+
use std::io::{Read, Write};
use std::process::exit;
@@ -191,9 +197,9 @@
let args = Ukey2Cli::parse();
let shell = Ukey2Shell::new(args.verification_string_length);
if args.mode == MODE_INITIATOR {
- shell.run_as_initiator();
+ let _ = shell.run_as_initiator();
} else if args.mode == MODE_RESPONDER {
- shell.run_as_responder();
+ let _ = shell.run_as_responder();
} else {
exit(1);
}
diff --git a/nearby/crypto/crypto_provider/Cargo.toml b/nearby/crypto/crypto_provider/Cargo.toml
index e7dd8ba..1a588bb 100644
--- a/nearby/crypto/crypto_provider/Cargo.toml
+++ b/nearby/crypto/crypto_provider/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
tinyvec.workspace = true
diff --git a/nearby/crypto/crypto_provider/benches/constant_time_eq_bench.rs b/nearby/crypto/crypto_provider/benches/constant_time_eq_bench.rs
index f401327..70c65cf 100644
--- a/nearby/crypto/crypto_provider/benches/constant_time_eq_bench.rs
+++ b/nearby/crypto/crypto_provider/benches/constant_time_eq_bench.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(missing_docs, clippy::indexing_slicing)]
+
use criterion::{
criterion_group, criterion_main, measurement::WallTime, BatchSize, BenchmarkGroup, Criterion,
};
@@ -33,7 +35,7 @@
fn add_benches<C: CryptoProvider>(group: &mut BenchmarkGroup<WallTime>, rng: &mut ThreadRng) {
const TEST_LEN: usize = 1000;
for i in (0..=TEST_LEN).step_by(100) {
- group.bench_function(
+ let _ = group.bench_function(
&format!(
"constant_time_eq impl {} differ by {:04} bytes",
std::any::type_name::<C>(),
diff --git a/nearby/crypto/crypto_provider/benches/hkdf_bench.rs b/nearby/crypto/crypto_provider/benches/hkdf_bench.rs
index 4c11d0d..e73f8cf 100644
--- a/nearby/crypto/crypto_provider/benches/hkdf_bench.rs
+++ b/nearby/crypto/crypto_provider/benches/hkdf_bench.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(missing_docs, clippy::expect_used)]
+
use criterion::{criterion_group, criterion_main, Criterion};
use hex_literal::hex;
@@ -26,15 +28,16 @@
let salt = hex!("000102030405060708090a0b0c");
let info = hex!("f0f1f2f3f4f5f6f7f8f9");
- c.bench_function(&format!("bench hkdf with salt {}", std::any::type_name::<C>()), |b| {
- b.iter(|| {
- 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 _ =
+ c.bench_function(&format!("bench hkdf with salt {}", std::any::type_name::<C>()), |b| {
+ b.iter(|| {
+ 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");
+ });
});
- });
- c.bench_function(&format!("bench hkdf no salt {}", std::any::type_name::<C>()), |b| {
+ let _ = c.bench_function(&format!("bench hkdf no salt {}", std::any::type_name::<C>()), |b| {
b.iter(|| {
let hk = C::HkdfSha256::new(None, &ikm);
let mut okm = [0u8; 42];
diff --git a/nearby/crypto/crypto_provider/benches/hmac_bench.rs b/nearby/crypto/crypto_provider/benches/hmac_bench.rs
index c7ccf1a..9bcfde0 100644
--- a/nearby/crypto/crypto_provider/benches/hmac_bench.rs
+++ b/nearby/crypto/crypto_provider/benches/hmac_bench.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(missing_docs)]
+
use criterion::{criterion_group, criterion_main, Criterion};
use crypto_provider::hmac::Hmac;
@@ -26,7 +28,7 @@
let key: [u8; 32] = rand_ext::random_bytes::<32, C>(&mut rng);
let update_data: [u8; 16] = rand_ext::random_bytes::<16, C>(&mut rng);
- c.bench_function("bench for hmac sha256 single update", |b| {
+ let _ = c.bench_function("bench for hmac sha256 single update", |b| {
b.iter(|| {
let mut hmac = C::HmacSha256::new_from_key(key);
hmac.update(&update_data);
@@ -40,7 +42,7 @@
let key: [u8; 64] = rand_ext::random_bytes::<64, C>(&mut rng);
let update_data: [u8; 16] = random_bytes::<16, C>(&mut rng);
- c.bench_function("bench for hmac sha512 single update", |b| {
+ let _ = c.bench_function("bench for hmac sha512 single update", |b| {
b.iter(|| {
let mut hmac = C::HmacSha512::new_from_key(key);
hmac.update(&update_data);
diff --git a/nearby/crypto/crypto_provider/src/aes/cbc.rs b/nearby/crypto/crypto_provider/src/aes/cbc.rs
index 59ce52d..82a857b 100644
--- a/nearby/crypto/crypto_provider/src/aes/cbc.rs
+++ b/nearby/crypto/crypto_provider/src/aes/cbc.rs
@@ -29,6 +29,7 @@
pub trait AesCbcPkcs7Padded {
/// Calculate the padded output length (e.g. output of `encrypt`) from the unpadded length (e.g.
/// input message of `encrypt`).
+ #[allow(clippy::expect_used)]
fn padded_output_len(unpadded_len: usize) -> usize {
(unpadded_len - (unpadded_len % 16))
.checked_add(16)
@@ -109,7 +110,7 @@
#[test]
#[should_panic]
fn test_padded_output_len_overflow() {
- AesCbcPkcs7PaddedStub::padded_output_len(usize::MAX);
+ let _ = AesCbcPkcs7PaddedStub::padded_output_len(usize::MAX);
}
struct AesCbcPkcs7PaddedStub;
diff --git a/nearby/crypto/crypto_provider/src/lib.rs b/nearby/crypto/crypto_provider/src/lib.rs
index 0031ebb..214175d 100644
--- a/nearby/crypto/crypto_provider/src/lib.rs
+++ b/nearby/crypto/crypto_provider/src/lib.rs
@@ -11,12 +11,11 @@
// 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)]
//! Crypto abstraction trait only crate, which provides traits for cryptographic primitives
+#![no_std]
+
use core::fmt::Debug;
use crate::aes::{Aes128Key, Aes256Key};
diff --git a/nearby/crypto/crypto_provider_default/Cargo.toml b/nearby/crypto/crypto_provider_default/Cargo.toml
index 2a155bf..4c906e4 100644
--- a/nearby/crypto/crypto_provider_default/Cargo.toml
+++ b/nearby/crypto/crypto_provider_default/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
crypto_provider.workspace = true
crypto_provider_rustcrypto = {workspace = true, optional = true}
diff --git a/nearby/crypto/crypto_provider_default/src/lib.rs b/nearby/crypto/crypto_provider_default/src/lib.rs
index b880ba8..52da9d4 100644
--- a/nearby/crypto/crypto_provider_default/src/lib.rs
+++ b/nearby/crypto/crypto_provider_default/src/lib.rs
@@ -16,8 +16,6 @@
//! feature flag.
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(missing_docs)]
cfg_if::cfg_if! {
if #[cfg(feature = "rustcrypto")] {
diff --git a/nearby/crypto/crypto_provider_openssl/Cargo.toml b/nearby/crypto/crypto_provider_openssl/Cargo.toml
index 84d4380..19ef3e4 100644
--- a/nearby/crypto/crypto_provider_openssl/Cargo.toml
+++ b/nearby/crypto/crypto_provider_openssl/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
crypto_provider = { workspace = true, features = ["alloc", "std"] }
crypto_provider_stubs.workspace = true
diff --git a/nearby/crypto/crypto_provider_openssl/src/aes.rs b/nearby/crypto/crypto_provider_openssl/src/aes.rs
index c2ac5b1..857be74 100644
--- a/nearby/crypto/crypto_provider_openssl/src/aes.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/aes.rs
@@ -71,7 +71,7 @@
let mut crypter =
Crypter::new(Cipher::aes_128_ecb(), Mode::Encrypt, self.0.as_slice(), None).unwrap();
crypter.pad(false);
- crypter.update(block, &mut output).unwrap();
+ let _ = crypter.update(block, &mut output).unwrap();
block.copy_from_slice(&output[..crypto_provider::aes::BLOCK_SIZE]);
}
}
@@ -83,7 +83,7 @@
let mut crypter =
Crypter::new(Cipher::aes_128_ecb(), Mode::Decrypt, self.0.as_slice(), None).unwrap();
crypter.pad(false);
- crypter.update(block, &mut output).unwrap();
+ let _ = crypter.update(block, &mut output).unwrap();
block.copy_from_slice(&output[..crypto_provider::aes::BLOCK_SIZE]);
}
}
@@ -106,7 +106,7 @@
let mut crypter =
Crypter::new(Cipher::aes_256_ecb(), Mode::Encrypt, self.0.as_slice(), None).unwrap();
crypter.pad(false);
- crypter.update(block, &mut output).unwrap();
+ let _ = crypter.update(block, &mut output).unwrap();
block.copy_from_slice(&output[..crypto_provider::aes::BLOCK_SIZE]);
}
}
@@ -118,7 +118,7 @@
let mut crypter =
Crypter::new(Cipher::aes_256_ecb(), Mode::Decrypt, self.0.as_slice(), None).unwrap();
crypter.pad(false);
- crypter.update(block, &mut output).unwrap();
+ let _ = crypter.update(block, &mut output).unwrap();
block.copy_from_slice(&output[..crypto_provider::aes::BLOCK_SIZE]);
}
}
diff --git a/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs b/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs
index d429a4d..b726f5f 100644
--- a/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/hkdf_openssl.rs
@@ -42,7 +42,9 @@
let md = H::get_md();
ctx.derive_init().expect("hkdf derive init should not fail");
ctx.set_hkdf_md(md).expect("hkdf set md should not fail");
- self.salt.as_ref().map(|salt| ctx.set_hkdf_salt(salt.as_slice()));
+ let _ = self.salt.as_ref().map(|salt| {
+ ctx.set_hkdf_salt(salt.as_slice()).expect("setting the salt is infallible")
+ });
ctx.set_hkdf_key(self.ikm.as_slice()).expect("should be able to set key");
ctx.add_hkdf_info(&info_components.concat()).expect("should be able to add info");
ctx.derive(Some(okm)).map_err(|_| InvalidLength).map(|_| ())
diff --git a/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs b/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs
index 9b86726..5272995 100644
--- a/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/hmac_boringssl.rs
@@ -50,7 +50,7 @@
fn finalize(mut self) -> [u8; N] {
let mut buf = [0_u8; N];
- self.ctx.finalize(&mut buf).expect("wrong length");
+ let _ = self.ctx.finalize(&mut buf).expect("wrong length");
buf
}
diff --git a/nearby/crypto/crypto_provider_openssl/src/lib.rs b/nearby/crypto/crypto_provider_openssl/src/lib.rs
index 8d1db1d..04b4e4c 100644
--- a/nearby/crypto/crypto_provider_openssl/src/lib.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/lib.rs
@@ -12,10 +12,13 @@
// 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.
-#![deny(missing_docs, clippy::indexing_slicing, clippy::panic)]
//! Crate which provides impls for CryptoProvider backed by openssl
+// This crate treats allocation errors as handleable, which leads to unwraps everywhere, so they
+// have to be allowed here. This will be fixed when we can migrate over to the new boringssl bindings
+#![allow(clippy::expect_used, clippy::unwrap_used)]
+
use cfg_if::cfg_if;
pub use openssl;
use openssl::hash::MessageDigest;
diff --git a/nearby/crypto/crypto_provider_openssl/src/sha2.rs b/nearby/crypto/crypto_provider_openssl/src/sha2.rs
index 92e663e..68fee79 100644
--- a/nearby/crypto/crypto_provider_openssl/src/sha2.rs
+++ b/nearby/crypto/crypto_provider_openssl/src/sha2.rs
@@ -38,7 +38,8 @@
mdctx.digest_init(Self::get_md()).unwrap();
mdctx.digest_update(input).unwrap();
let mut buf = [0_u8; 32];
- mdctx.digest_final(&mut buf).unwrap();
+ let size = mdctx.digest_final(&mut buf).unwrap();
+ debug_assert_eq!(size, 32);
buf
}
}
@@ -63,7 +64,8 @@
mdctx.digest_init(Self::get_md()).unwrap();
mdctx.digest_update(input).unwrap();
let mut buf = [0_u8; 64];
- mdctx.digest_final(&mut buf).unwrap();
+ let size = mdctx.digest_final(&mut buf).unwrap();
+ debug_assert_eq!(size, 64);
buf
}
}
diff --git a/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
index a0638ff..14e8ad9 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
+++ b/nearby/crypto/crypto_provider_rustcrypto/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
aead = "0.5.1"
aes-gcm-siv = { version = "0.11.1", features = [
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
index 628f679..2985dec 100644
--- a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
+++ b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
@@ -11,15 +11,8 @@
// 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
diff --git a/nearby/crypto/rand_core_05_adapter/Cargo.toml b/nearby/crypto/rand_core_05_adapter/Cargo.toml
index 0a8fc47..1a02526 100644
--- a/nearby/crypto/rand_core_05_adapter/Cargo.toml
+++ b/nearby/crypto/rand_core_05_adapter/Cargo.toml
@@ -4,9 +4,10 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
rand.workspace = true
# an older rand_core used by ed25519-dalek so we can adapt newer rand to it
rand_core05 = { package = "rand_core", version = "0.5.1" }
-
-[dev-dependencies]
diff --git a/nearby/crypto/rand_core_05_adapter/src/lib.rs b/nearby/crypto/rand_core_05_adapter/src/lib.rs
index 6484983..9de0020 100644
--- a/nearby/crypto/rand_core_05_adapter/src/lib.rs
+++ b/nearby/crypto/rand_core_05_adapter/src/lib.rs
@@ -13,15 +13,8 @@
// limitations under the License.
//! Adapter for using rand_core 0.5 RNGs with code that expects rand_core 0.5 RNGs.
+
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::indexing_slicing,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used
-)]
/// A trivial adapter to expose rand 1.0/rand_core 0.6 rngs to ed25519-dalek's rand_core 0.5 types,
/// which we import under a separate name so there's no clash.
diff --git a/nearby/presence/array_ref/Cargo.toml b/nearby/presence/array_ref/Cargo.toml
index f912c41..b74168b 100644
--- a/nearby/presence/array_ref/Cargo.toml
+++ b/nearby/presence/array_ref/Cargo.toml
@@ -4,8 +4,10 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
std = []
-[dependencies]
diff --git a/nearby/presence/array_ref/src/lib.rs b/nearby/presence/array_ref/src/lib.rs
index 3ff84fc..769d3ef 100644
--- a/nearby/presence/array_ref/src/lib.rs
+++ b/nearby/presence/array_ref/src/lib.rs
@@ -12,8 +12,6 @@
// 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.
-#![forbid(unsafe_code)]
-#![deny(missing_docs)]
//! Crate exposing macros to take array references of slices
diff --git a/nearby/presence/array_view/Cargo.toml b/nearby/presence/array_view/Cargo.toml
index 48693c4..8ac53d2 100644
--- a/nearby/presence/array_view/Cargo.toml
+++ b/nearby/presence/array_view/Cargo.toml
@@ -4,11 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
std = []
-
-[dependencies]
-
-[dev-dependencies]
-
diff --git a/nearby/presence/array_view/src/lib.rs b/nearby/presence/array_view/src/lib.rs
index c57e959..e2ea8d4 100644
--- a/nearby/presence/array_view/src/lib.rs
+++ b/nearby/presence/array_view/src/lib.rs
@@ -14,14 +14,6 @@
//! A no_std friendly array wrapper to expose a variable length prefix of the array.
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::indexing_slicing,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used
-)]
#[cfg(feature = "std")]
extern crate std;
diff --git a/nearby/presence/ldt/Cargo.toml b/nearby/presence/ldt/Cargo.toml
index 2ee7b4c..337dd0d 100644
--- a/nearby/presence/ldt/Cargo.toml
+++ b/nearby/presence/ldt/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
std = []
@@ -13,7 +16,7 @@
ldt_tbc.workspace = true
[dev-dependencies]
-crypto_provider_default = {workspace = true, features = ["rustcrypto"]}
+crypto_provider_default = { workspace = true, features = ["rustcrypto"] }
rand_ext.workspace = true
test_helper.workspace = true
xts_aes.workspace = true
@@ -21,7 +24,7 @@
rand.workspace = true
rand_pcg.workspace = true
base64.workspace = true
-serde_json = {workspace = true, features = ["std"]}
+serde_json = { workspace = true, features = ["std"] }
anyhow.workspace = true
hex.workspace = true
diff --git a/nearby/presence/ldt/benches/ldt_scan.rs b/nearby/presence/ldt/benches/ldt_scan.rs
index dac1374..b1711ad 100644
--- a/nearby/presence/ldt/benches/ldt_scan.rs
+++ b/nearby/presence/ldt/benches/ldt_scan.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(missing_docs, unused_results, clippy::indexing_slicing, clippy::unwrap_used)]
+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use crypto_provider::{CryptoProvider, CryptoRng};
use crypto_provider_rustcrypto::RustCrypto;
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 517e7ec..7e7c943 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
@@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//! Generates LDT test vectors which can be used to verify implementations
+
+#![allow(clippy::unwrap_used)]
+
use crypto_provider::aes::BLOCK_SIZE;
use crypto_provider::{aes, CryptoProvider, CryptoRng};
use crypto_provider_rustcrypto::RustCrypto;
diff --git a/nearby/presence/ldt/examples/ldt_benchmark.rs b/nearby/presence/ldt/examples/ldt_benchmark.rs
index df87c28..101e17b 100644
--- a/nearby/presence/ldt/examples/ldt_benchmark.rs
+++ b/nearby/presence/ldt/examples/ldt_benchmark.rs
@@ -14,6 +14,8 @@
//! A manual benchmark for more interactive parameter-twiddling.
+#![allow(clippy::unwrap_used, clippy::indexing_slicing)]
+
use clap::Parser as _;
use crypto_provider_rustcrypto::RustCrypto;
use ldt::{LdtDecryptCipher, LdtEncryptCipher, LdtKey, Mix, Swap, XorPadder};
diff --git a/nearby/presence/ldt/examples/ldt_prp.rs b/nearby/presence/ldt/examples/ldt_prp.rs
index f8e055c..7734952 100644
--- a/nearby/presence/ldt/examples/ldt_prp.rs
+++ b/nearby/presence/ldt/examples/ldt_prp.rs
@@ -20,6 +20,9 @@
//!
//! The output shows how many times a change to the first n bytes wasn't detected, as well as a
//! histogram of how many bits were flipped in the entire plaintext.
+
+#![allow(clippy::unwrap_used, clippy::indexing_slicing)]
+
use clap::{self, Parser as _};
use crypto_provider::aes::BLOCK_SIZE;
use crypto_provider::{CryptoProvider, CryptoRng};
diff --git a/nearby/presence/ldt/src/lib.rs b/nearby/presence/ldt/src/lib.rs
index 9065e12..8596ad2 100644
--- a/nearby/presence/ldt/src/lib.rs
+++ b/nearby/presence/ldt/src/lib.rs
@@ -15,8 +15,6 @@
//! Provides an implementation of [LDT](https://eprint.iacr.org/2017/841.pdf).
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(clippy::indexing_slicing, clippy::unwrap_used, clippy::panic, clippy::expect_used)]
#[cfg(feature = "std")]
extern crate std;
diff --git a/nearby/presence/ldt/tests/ldt_roundtrip.rs b/nearby/presence/ldt/tests/ldt_roundtrip.rs
index b5f930e..251cefe 100644
--- a/nearby/presence/ldt/tests/ldt_roundtrip.rs
+++ b/nearby/presence/ldt/tests/ldt_roundtrip.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use crypto_provider::aes::BLOCK_SIZE;
use crypto_provider::{CryptoProvider, CryptoRng};
use crypto_provider_default::CryptoProviderImpl;
diff --git a/nearby/presence/ldt/tests/ldt_test_vectors.rs b/nearby/presence/ldt/tests/ldt_test_vectors.rs
index 477243d..03b5d3f 100644
--- a/nearby/presence/ldt/tests/ldt_test_vectors.rs
+++ b/nearby/presence/ldt/tests/ldt_test_vectors.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used, clippy::indexing_slicing)]
+
use anyhow::anyhow;
use crypto_provider_default::CryptoProviderImpl;
use ldt::{DefaultPadder, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Swap, XorPadder};
@@ -26,7 +28,7 @@
);
let mut file = fs::File::open(full_path)?;
let mut data = String::new();
- file.read_to_string(&mut data)?;
+ let _ = file.read_to_string(&mut data)?;
let test_cases = match serde_json::de::from_str(&data)? {
serde_json::Value::Array(a) => a,
_ => return Err(anyhow!("bad json")),
@@ -73,7 +75,7 @@
test_helper::get_data_file("presence/ldt/resources/test/ldt-xor-pad-testvectors.json");
let mut file = fs::File::open(full_path)?;
let mut data = String::new();
- file.read_to_string(&mut data)?;
+ let _ = file.read_to_string(&mut data)?;
let test_cases = match serde_json::de::from_str(&data)? {
serde_json::Value::Array(a) => a,
_ => return Err(anyhow!("bad json")),
diff --git a/nearby/presence/ldt/tests/tests.rs b/nearby/presence/ldt/tests/tests.rs
index b9e061a..25938fb 100644
--- a/nearby/presence/ldt/tests/tests.rs
+++ b/nearby/presence/ldt/tests/tests.rs
@@ -70,7 +70,8 @@
fn normal_pad_too_big_panics() {
let padder = DefaultPadder;
let input = [0x99; 16];
- <DefaultPadder as Padder<16, XtsAes128<CryptoProviderImpl>>>::pad_tweak(&padder, &input);
+ let _ =
+ <DefaultPadder as Padder<16, XtsAes128<CryptoProviderImpl>>>::pad_tweak(&padder, &input);
}
#[test]
@@ -129,7 +130,7 @@
let padder = [0x24; BLOCK_SIZE].into();
// need 1 byte for padding, and 2 more for salt
let input = [0x99; 16];
- <XorPadder<BLOCK_SIZE> as Padder<BLOCK_SIZE, XtsAes128<CryptoProviderImpl>>>::pad_tweak(
+ let _ = <XorPadder<BLOCK_SIZE> as Padder<BLOCK_SIZE, XtsAes128<CryptoProviderImpl>>>::pad_tweak(
&padder, &input,
);
}
diff --git a/nearby/presence/ldt_np_adv/Cargo.toml b/nearby/presence/ldt_np_adv/Cargo.toml
index 522e97b..3f19bdd 100644
--- a/nearby/presence/ldt_np_adv/Cargo.toml
+++ b/nearby/presence/ldt_np_adv/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
std = []
diff --git a/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs b/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs
index d7d7fad..7c0b4aa 100644
--- a/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs
+++ b/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(missing_docs)]
+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use ldt_np_adv::*;
@@ -30,7 +32,7 @@
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 _ = 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);
@@ -42,7 +44,7 @@
black_box(find_matching_item::<C>(&ciphers, salt, &payload))
});
});
- c.bench_function(&format!("Scan adv with existing ciphers/{len}"), |b| {
+ let _ = 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);
@@ -64,7 +66,7 @@
payload: &[u8],
) {
let padder = salt_padder::<16, C>(salt);
- ciphers
+ let _ = ciphers
.iter()
.enumerate()
.filter_map(|(index, item)| {
diff --git a/nearby/presence/ldt_np_adv/src/lib.rs b/nearby/presence/ldt_np_adv/src/lib.rs
index 31aa50d..542d6a5 100644
--- a/nearby/presence/ldt_np_adv/src/lib.rs
+++ b/nearby/presence/ldt_np_adv/src/lib.rs
@@ -14,14 +14,6 @@
//! Nearby Presence-specific usage of LDT.
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::indexing_slicing,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used
-)]
#[cfg(feature = "std")]
extern crate std;
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 90d09b1..cf176dd 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
@@ -33,7 +33,7 @@
test_helper::get_data_file("presence/ldt_np_adv/resources/test/np_adv_test_vectors.json");
let mut file = fs::File::open(full_path)?;
let mut data = String::new();
- file.read_to_string(&mut data)?;
+ let _ = file.read_to_string(&mut data)?;
let test_cases = match serde_json::de::from_str(&data)? {
serde_json::Value::Array(a) => a,
_ => return Err(anyhow!("bad json")),
diff --git a/nearby/presence/ldt_np_jni/Cargo.toml b/nearby/presence/ldt_np_jni/Cargo.toml
index 6803d56..2551c14 100644
--- a/nearby/presence/ldt_np_jni/Cargo.toml
+++ b/nearby/presence/ldt_np_jni/Cargo.toml
@@ -4,12 +4,15 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
ldt.workspace = true
ldt_np_adv.workspace = true
np_hkdf.workspace = true
crypto_provider.workspace = true
-crypto_provider_default = {workspace = true, default-features = false}
+crypto_provider_default = { workspace = true, default-features = false }
cfg-if.workspace = true
jni.workspace = true
diff --git a/nearby/presence/ldt_np_jni/src/lib.rs b/nearby/presence/ldt_np_jni/src/lib.rs
index 538a44e..e232c1e 100644
--- a/nearby/presence/ldt_np_jni/src/lib.rs
+++ b/nearby/presence/ldt_np_jni/src/lib.rs
@@ -23,7 +23,7 @@
// We are not actually no_std because the jni crate is pulling it in, but at least this enforces
// that this lib isn't using anything from the std lib
#![no_std]
-#![deny(missing_docs)]
+#![allow(unsafe_code)]
// Allow using Box in no_std
extern crate alloc;
@@ -86,6 +86,7 @@
})?;
let hkdf_key_seed = NpKeySeedHkdf::<CryptoProviderImpl>::new(
+ #[allow(clippy::expect_used)]
key_seed.as_slice().try_into().expect("Length is checked above"),
);
@@ -122,9 +123,11 @@
}
})?;
let hkdf_key_seed = NpKeySeedHkdf::<CryptoProviderImpl>::new(
+ #[allow(clippy::expect_used)]
key_seed.as_slice().try_into().expect("Length is checked above"),
);
+ #[allow(clippy::expect_used)]
let cipher = ldt_np_adv::build_np_adv_decrypter_from_key_seed::<CryptoProviderImpl>(
&hkdf_key_seed,
hmac_tag.as_slice().try_into().expect("Length is checked above"),
@@ -252,7 +255,7 @@
let ret = f(&boxed);
// don't consume the box -- need to keep the handle alive
- Box::leak(boxed);
+ let _ = Box::leak(boxed);
ret
}
diff --git a/nearby/presence/ldt_tbc/Cargo.toml b/nearby/presence/ldt_tbc/Cargo.toml
index 0177f87..8941051 100644
--- a/nearby/presence/ldt_tbc/Cargo.toml
+++ b/nearby/presence/ldt_tbc/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
std = []
diff --git a/nearby/presence/ldt_tbc/src/lib.rs b/nearby/presence/ldt_tbc/src/lib.rs
index d24da7e..aefeb17 100644
--- a/nearby/presence/ldt_tbc/src/lib.rs
+++ b/nearby/presence/ldt_tbc/src/lib.rs
@@ -12,14 +12,6 @@
// 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.
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::indexing_slicing,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used
-)]
//! Defining traits for an LDT specific Tweakable Block Cipher
diff --git a/nearby/presence/np_adv/Cargo.toml b/nearby/presence/np_adv/Cargo.toml
index 97e12f5..e502c35 100644
--- a/nearby/presence/np_adv/Cargo.toml
+++ b/nearby/presence/np_adv/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
array_view = { path = "../array_view" }
ldt_np_adv.workspace = true
@@ -29,8 +32,7 @@
hex.workspace = true
rand.workspace = true
rand_ext = { path = "../rand_ext" }
-init_with = "1.1.0"
-serde_json = {workspace = true, features = ["std"]}
+serde_json = { workspace = true, features = ["std"] }
serde.workspace = true
anyhow.workspace = true
test_helper = { path = "../test_helper" }
diff --git a/nearby/presence/np_adv/benches/deser_adv.rs b/nearby/presence/np_adv/benches/deser_adv.rs
index e998047..08fd5c4 100644
--- a/nearby/presence/np_adv/benches/deser_adv.rs
+++ b/nearby/presence/np_adv/benches/deser_adv.rs
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(
+ missing_docs,
+ unused_results,
+ clippy::unwrap_used,
+ clippy::expect_used,
+ clippy::indexing_slicing,
+ clippy::panic
+)]
+
use core::marker::PhantomData;
use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion};
use crypto_provider::{CryptoProvider, CryptoRng};
diff --git a/nearby/presence/np_adv/src/array_vec.rs b/nearby/presence/np_adv/src/array_vec.rs
index a92ff5b..bcc387e 100644
--- a/nearby/presence/np_adv/src/array_vec.rs
+++ b/nearby/presence/np_adv/src/array_vec.rs
@@ -89,12 +89,14 @@
/// (i.e., does not allocate), and *O*(*m* \* *n* \* log(*n*)) worst-case,
/// where the key function is *O*(*m*).
pub fn sort_unstable_by_key<K: Ord>(&mut self, f: impl Fn(&A) -> K) {
- self.0.sort_unstable_by_key(|a| f(a.as_ref().unwrap()))
+ self.0.sort_unstable_by_key(|a| {
+ f(a.as_ref().expect("Iterated values in ArrayVecOption should never be None"))
+ })
}
/// Remove an element, swapping the end of the vec into its place.
pub fn swap_remove(&mut self, index: usize) -> A {
- self.0.swap_remove(index).unwrap()
+ self.0.swap_remove(index).expect("since index is is bounds, the value at index will always be Some which is safe to unwrap")
}
/// Converts this vector into a regular `Vec`, unwrapping all of the
@@ -125,7 +127,7 @@
impl<A, const N: usize> core::ops::Index<usize> for ArrayVecOption<A, N> {
type Output = A;
fn index(&self, index: usize) -> &Self::Output {
- self.0[index].as_ref().unwrap()
+ self.0[index].as_ref().expect("This panics if provided index is out of bounds")
}
}
@@ -167,7 +169,7 @@
assert_eq!(Some(&5_u32), vec.get(4));
assert_eq!(vec![1_u32, 2, 3, 4, 5], vec.clone().into_vec());
- vec.swap_remove(2);
+ let _ = vec.swap_remove(2);
assert_eq!(vec![1_u32, 2, 5, 4], vec.clone().into_vec());
}
diff --git a/nearby/presence/np_adv/src/credential/v1.rs b/nearby/presence/np_adv/src/credential/v1.rs
index 7d060f2..386799f 100644
--- a/nearby/presence/np_adv/src/credential/v1.rs
+++ b/nearby/presence/np_adv/src/credential/v1.rs
@@ -18,7 +18,7 @@
protocol_version_seal, BroadcastCryptoMaterial, DiscoveryCryptoMaterial, ProtocolVersion,
};
use crate::MetadataKey;
-use crypto_provider::{aes::Aes128Key, ed25519, CryptoProvider, CryptoRng};
+use crypto_provider::{aes::Aes128Key, ed25519, ed25519::PublicKey, CryptoProvider, CryptoRng};
use np_hkdf::UnsignedSectionKeys;
/// Cryptographic information about a particular V1 discovery credential
@@ -32,17 +32,17 @@
}
impl V1DiscoveryCredential {
/// Construct a V1 discovery credential from the provided identity data.
- pub fn new<C: CryptoProvider>(
+ pub fn new(
key_seed: [u8; 32],
expected_unsigned_metadata_key_hmac: [u8; 32],
expected_signed_metadata_key_hmac: [u8; 32],
- pub_key: np_ed25519::PublicKey<C>,
+ pub_key: ed25519::RawPublicKey,
) -> Self {
Self {
key_seed,
expected_unsigned_metadata_key_hmac,
expected_signed_metadata_key_hmac,
- pub_key: pub_key.to_bytes(),
+ pub_key,
}
}
@@ -400,7 +400,7 @@
let key_seed = self.key_seed();
let metadata_key = self.metadata_key();
let pub_key = self.signing_key().derive_public_key::<C::Ed25519>();
- let pub_key = np_ed25519::PublicKey::<C>::new(pub_key);
+ let pub_key = pub_key.to_bytes();
let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed);
let unsigned = hkdf
diff --git a/nearby/presence/np_adv/src/deser_v0_tests.rs b/nearby/presence/np_adv/src/deser_v0_tests.rs
index 93c3b97..f6643de 100644
--- a/nearby/presence/np_adv/src/deser_v0_tests.rs
+++ b/nearby/presence/np_adv/src/deser_v0_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use rand::{seq::SliceRandom as _, SeedableRng as _};
extern crate std;
diff --git a/nearby/presence/np_adv/src/deser_v1_tests.rs b/nearby/presence/np_adv/src/deser_v1_tests.rs
index 903ed3d..cea0063 100644
--- a/nearby/presence/np_adv/src/deser_v1_tests.rs
+++ b/nearby/presence/np_adv/src/deser_v1_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use core::marker::PhantomData;
use rand::{rngs::StdRng, seq::SliceRandom as _, Rng as _, SeedableRng as _};
diff --git a/nearby/presence/np_adv/src/extended/data_elements/tests.rs b/nearby/presence/np_adv/src/extended/data_elements/tests.rs
index a0f9a2f..6f085cd 100644
--- a/nearby/presence/np_adv/src/extended/data_elements/tests.rs
+++ b/nearby/presence/np_adv/src/extended/data_elements/tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use super::*;
diff --git a/nearby/presence/np_adv/src/extended/de_type.rs b/nearby/presence/np_adv/src/extended/de_type.rs
index 105d15e..975df90 100644
--- a/nearby/presence/np_adv/src/extended/de_type.rs
+++ b/nearby/presence/np_adv/src/extended/de_type.rs
@@ -36,7 +36,7 @@
impl From<u8> for DeType {
fn from(value: u8) -> Self {
- DeType { code: value as u32 }
+ DeType { code: value.into() }
}
}
@@ -46,6 +46,12 @@
}
}
+impl From<DeType> for u32 {
+ fn from(value: DeType) -> Self {
+ value.code
+ }
+}
+
pub(crate) trait ExtendedDataElementType: Sized {
/// A type code for use in the DE header.
fn type_code(&self) -> DeType;
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mic_decrypt_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mic_decrypt_tests.rs
index 9bd54b8..bf78b7d 100644
--- a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mic_decrypt_tests.rs
+++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mic_decrypt_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use super::*;
@@ -190,7 +192,7 @@
let mut expected = Vec::new();
// battery de
expected.extend_from_slice(txpower_de.clone().de_header().serialize().as_slice());
- txpower_de.write_de_contents(&mut expected);
+ let _ = txpower_de.write_de_contents(&mut expected);
assert_eq!(metadata_key, decrypted.metadata_key_plaintext);
assert_eq!(&expected, decrypted.plaintext_contents);
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs
index 2236630..eb2fe01 100644
--- a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs
+++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs
@@ -123,8 +123,7 @@
let mut result = Vec::new();
result.extend_from_slice(&self.metadata_key_plaintext.0);
result.extend_from_slice(self.plaintext_contents);
- // Won't panic because of the involved lengths
- ArrayView::try_from_slice(&result).unwrap()
+ ArrayView::try_from_slice(&result).expect("Won't panic because of the involved lengths")
}
}
@@ -181,8 +180,10 @@
&self,
) -> SectionIdentityResolutionContents {
let nonce = self.compute_nonce::<C>();
- let metadata_key_ciphertext: [u8; METADATA_KEY_LEN] =
- self.all_ciphertext[..METADATA_KEY_LEN].try_into().unwrap();
+ let metadata_key_ciphertext: [u8; METADATA_KEY_LEN] = self.all_ciphertext
+ [..METADATA_KEY_LEN]
+ .try_into()
+ .expect("slice will always fit into same size array");
SectionIdentityResolutionContents { nonce, metadata_key_ciphertext }
}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/signature_decrypt_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/signature_decrypt_tests.rs
index 2370aeb..af70228 100644
--- a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/signature_decrypt_tests.rs
+++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/signature_decrypt_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use crate::deserialization_arena;
@@ -127,11 +129,11 @@
// plaintext is correct
{
- let crypto_material = V1DiscoveryCredential::new::<CryptoProviderImpl>(
+ let crypto_material = V1DiscoveryCredential::new(
key_seed,
key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().calculate_hmac(&metadata_key.0),
key_seed_hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0),
- key_pair.public(),
+ key_pair.public().to_bytes(),
);
let signed_identity_resolution_material =
crypto_material.signed_identity_resolution_material::<CryptoProviderImpl>();
@@ -150,7 +152,7 @@
let mut expected = Vec::new();
expected.extend_from_slice(txpower_de.de_header().serialize().as_slice());
- txpower_de.write_de_contents(&mut expected);
+ let _ = txpower_de.write_de_contents(&mut expected);
let nonce: AesCtrNonce = section_salt.derive(Some(1.into())).unwrap();
@@ -177,11 +179,11 @@
// deserialization to Section works
{
- let crypto_material = V1DiscoveryCredential::new::<CryptoProviderImpl>(
+ let crypto_material = V1DiscoveryCredential::new(
key_seed,
key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().calculate_hmac(&metadata_key.0),
key_seed_hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0),
- key_pair.public(),
+ key_pair.public().to_bytes(),
);
let signed_identity_resolution_material =
crypto_material.signed_identity_resolution_material::<CryptoProviderImpl>();
@@ -524,11 +526,11 @@
contents
);
- let crypto_material = V1DiscoveryCredential::new::<CryptoProviderImpl>(
+ let crypto_material = V1DiscoveryCredential::new(
key_seed,
key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().calculate_hmac(&metadata_key.0),
key_seed_hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0),
- key_pair.public(),
+ key_pair.public().to_bytes(),
);
let identity_resolution_material =
crypto_material.signed_identity_resolution_material::<CryptoProviderImpl>();
diff --git a/nearby/presence/np_adv/src/extended/deserialize/mod.rs b/nearby/presence/np_adv/src/extended/deserialize/mod.rs
index 4b78a32..6ec7881 100644
--- a/nearby/presence/np_adv/src/extended/deserialize/mod.rs
+++ b/nearby/presence/np_adv/src/extended/deserialize/mod.rs
@@ -17,7 +17,7 @@
#[cfg(any(test, feature = "alloc"))]
extern crate alloc;
-#[cfg(any(test, feature = "alloc"))]
+#[cfg(any(test, feature = "alloc", feature = "devtools"))]
use alloc::vec::Vec;
use core::array::TryFromSliceError;
@@ -845,8 +845,11 @@
}
fn salt(&self) -> RawV1Salt {
- // should never panic
- RawV1Salt(self.bytes[Self::TOTAL_DE_LEN - 16..].try_into().ok().unwrap())
+ RawV1Salt(
+ self.bytes[Self::TOTAL_DE_LEN - 16..]
+ .try_into()
+ .expect("a 16 byte slice will always fit into a 16 byte array"),
+ )
}
}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/parse_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/parse_tests.rs
index 4afa3ec..41eb054 100644
--- a/nearby/presence/np_adv/src/extended/deserialize/parse_tests.rs
+++ b/nearby/presence/np_adv/src/extended/deserialize/parse_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use super::*;
use crate::extended::deserialize::encrypted_section::{
@@ -461,7 +463,7 @@
adv_body.extend_from_slice(&[0x81]);
}
if remove_section_len {
- adv_body.remove(0);
+ let _ = adv_body.remove(0);
}
let ordered_adv = adv_body.clone();
@@ -476,7 +478,7 @@
// * the identity does not follow the section length
// * the section length is 0
if remove_section_len || !add_public_identity || (ordered_adv != adv_body) {
- parse_sections(V1Header { header_byte: 0x20 }, &adv_body)
+ let _ = parse_sections(V1Header { header_byte: 0x20 }, &adv_body)
.expect_err("Expected to fail because of missing section length or identity");
}
}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/section_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/section_tests.rs
index 5b1290f..f7e2025 100644
--- a/nearby/presence/np_adv/src/extended/deserialize/section_tests.rs
+++ b/nearby/presence/np_adv/src/extended/deserialize/section_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use super::*;
@@ -143,7 +145,7 @@
// Verify that the decrypted metadata contains the chosen index
let decrypted_metadata = matched_section.decrypt_metadata::<CryptoProviderImpl>().unwrap();
- assert_eq!(&[chosen_index as u8] as &[u8], &decrypted_metadata);
+ assert_eq!([chosen_index as u8].as_slice(), &decrypted_metadata);
// Verify that the section contents passed through unaltered
let section = matched_section.contents();
@@ -254,7 +256,7 @@
// Verify that the decrypted metadata contains the chosen index
let decrypted_metadata = matched_section.decrypt_metadata::<CryptoProviderImpl>().unwrap();
- assert_eq!(&[chosen_index as u8] as &[u8], &decrypted_metadata);
+ assert_eq!([chosen_index as u8].as_slice(), &decrypted_metadata);
// Verify that the section contents passed through unaltered
let section = matched_section.contents();
@@ -411,7 +413,7 @@
} else {
panic!("incorrect header");
};
- parse_sections(v1_header, remaining).expect_err("Expected an error");
+ let _ = parse_sections(v1_header, remaining).expect_err("Expected an error");
}
#[test]
@@ -424,7 +426,7 @@
} else {
panic!("incorrect header");
};
- parse_sections(v1_header, remaining).expect_err("Expected an error");
+ let _ = parse_sections(v1_header, remaining).expect_err("Expected an error");
}
#[test]
@@ -463,7 +465,7 @@
} else {
panic!("incorrect header");
};
- parse_sections(v1_header, remaining)
+ let _ = parse_sections(v1_header, remaining)
.expect_err("Expected an error because number of sections is over limit");
}
@@ -557,7 +559,7 @@
des.iter()
.map(|de| {
let mut buf = vec![];
- de.write_de_contents(&mut buf);
+ let _ = de.write_de_contents(&mut buf);
de.de_header().serialize().len() + buf.len()
})
.sum()
diff --git a/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs b/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs
index 36e4e5f..ee44c75 100644
--- a/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs
+++ b/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use super::*;
use crate::extended::serialize::section_tests::{fill_section_builder, DummyDataElement};
diff --git a/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs b/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs
index eda8b69..cb6c9ef 100644
--- a/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs
+++ b/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use super::*;
use crate::extended::deserialize;
use core::cmp;
diff --git a/nearby/presence/np_adv/src/extended/serialize/mod.rs b/nearby/presence/np_adv/src/extended/serialize/mod.rs
index f736dea..e753281 100644
--- a/nearby/presence/np_adv/src/extended/serialize/mod.rs
+++ b/nearby/presence/np_adv/src/extended/serialize/mod.rs
@@ -537,7 +537,7 @@
before_sig.split_at(EncryptionInfo::TOTAL_DE_LEN);
let encryption_info: &[u8; EncryptionInfo::TOTAL_DE_LEN] =
- encryption_info.try_into().unwrap();
+ encryption_info.try_into().expect("encryption info should always be the correct size");
// we need to sign the 16-byte IV, which doesn't have to actually fit in the adv, but we
// don't need a bigger buffer here since we won't be including the 66 bytes for the sig +
diff --git a/nearby/presence/np_adv/src/extended/serialize/section_tests.rs b/nearby/presence/np_adv/src/extended/serialize/section_tests.rs
index d418a50..68e5b60 100644
--- a/nearby/presence/np_adv/src/extended/serialize/section_tests.rs
+++ b/nearby/presence/np_adv/src/extended/serialize/section_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use super::*;
@@ -129,7 +131,7 @@
for de in extra_des {
plaintext.extend_from_slice(de.de_header().serialize().as_slice());
- de.write_de_contents(&mut plaintext);
+ let _ = de.write_de_contents(&mut plaintext);
}
cipher.apply_keystream(&mut plaintext);
@@ -232,7 +234,7 @@
let mut section_body = Vec::new();
for de in extra_des {
section_body.extend_from_slice(de.de_header().serialize().as_slice());
- de.write_de_contents(&mut section_body);
+ let _ = de.write_de_contents(&mut section_body);
}
let sig_payload = SectionSignaturePayload::from_deserialized_parts(
@@ -692,7 +694,7 @@
for de in extra_des {
plaintext.extend_from_slice(de.de_header().serialize().as_slice());
- de.write_de_contents(&mut plaintext);
+ let _ = de.write_de_contents(&mut plaintext);
}
cipher.apply_keystream(&mut plaintext);
@@ -765,7 +767,7 @@
let mut section_body = Vec::new();
for de in extra_des {
section_body.extend_from_slice(de.de_header().serialize().as_slice());
- de.write_de_contents(&mut section_body);
+ let _ = de.write_de_contents(&mut section_body);
}
let nonce = section_salt.derive(Some(1.into())).unwrap();
diff --git a/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs b/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs
index 24e6046..d03ad9b 100644
--- a/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs
+++ b/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use crate::extended::serialize::AdvertisementType;
@@ -42,7 +44,7 @@
);
let mut file = fs::File::open(full_path)?;
let mut data = String::new();
- file.read_to_string(&mut data)?;
+ let _ = file.read_to_string(&mut data)?;
let test_cases = match serde_json::de::from_str(&data)? {
serde_json::Value::Array(a) => a,
diff --git a/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs b/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs
index 946c969..ffdeeb9 100644
--- a/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs
+++ b/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use super::super::*;
use crate::legacy::actions::{ActionBits, InstantTethering, NearbyShare};
use crate::legacy::{Ciphertext, Plaintext};
diff --git a/nearby/presence/np_adv/src/header_parse_tests.rs b/nearby/presence/np_adv/src/header_parse_tests.rs
index 2da1b4a..f6b5533 100644
--- a/nearby/presence/np_adv/src/header_parse_tests.rs
+++ b/nearby/presence/np_adv/src/header_parse_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use super::*;
extern crate std;
diff --git a/nearby/presence/np_adv/src/legacy/actions/tests.rs b/nearby/presence/np_adv/src/legacy/actions/tests.rs
index 86b7a08..d45d968 100644
--- a/nearby/presence/np_adv/src/legacy/actions/tests.rs
+++ b/nearby/presence/np_adv/src/legacy/actions/tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use crate::legacy::{
diff --git a/nearby/presence/np_adv/src/legacy/de_type/mod.rs b/nearby/presence/np_adv/src/legacy/de_type/mod.rs
index 5c7ebfa..304347d 100644
--- a/nearby/presence/np_adv/src/legacy/de_type/mod.rs
+++ b/nearby/presence/np_adv/src/legacy/de_type/mod.rs
@@ -47,6 +47,7 @@
}
}
+/// The DE type code is out of range for v0 DE types.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(crate) struct DeTypeCodeOutOfRange;
diff --git a/nearby/presence/np_adv/src/legacy/de_type/tests.rs b/nearby/presence/np_adv/src/legacy/de_type/tests.rs
index 59075aa..fc64321 100644
--- a/nearby/presence/np_adv/src/legacy/de_type/tests.rs
+++ b/nearby/presence/np_adv/src/legacy/de_type/tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use super::*;
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/mod.rs b/nearby/presence/np_adv/src/legacy/deserialize/mod.rs
index 938045d..d6c6b36 100644
--- a/nearby/presence/np_adv/src/legacy/deserialize/mod.rs
+++ b/nearby/presence/np_adv/src/legacy/deserialize/mod.rs
@@ -359,6 +359,33 @@
TxPower(TxPowerDataElement),
}
+impl<F: PacketFlavor> PlainDataElement<F> {
+ /// Returns the DE type as a u8
+ #[cfg(feature = "devtools")]
+ pub fn de_type_code(&self) -> u8 {
+ match self {
+ PlainDataElement::Actions(_) => DataElementType::Actions.type_code().as_u8(),
+ PlainDataElement::TxPower(_) => DataElementType::TxPower.type_code().as_u8(),
+ }
+ }
+
+ /// Returns the serialized contents of the DE
+ #[cfg(feature = "devtools")]
+ pub fn de_contents(&self) -> alloc::vec::Vec<u8> {
+ use crate::legacy::serialize::{DataElementBundle, ToDataElementBundle};
+ match self {
+ PlainDataElement::Actions(a) => {
+ let bundle: DataElementBundle<F> = a.to_de_bundle();
+ bundle.contents_as_slice().to_vec()
+ }
+ PlainDataElement::TxPower(t) => {
+ let bundle: DataElementBundle<F> = t.to_de_bundle();
+ bundle.contents_as_slice().to_vec()
+ }
+ }
+ }
+}
+
/// The contents of a plaintext advertisement after deserializing DE contents
#[derive(Debug, PartialEq, Eq)]
pub struct PlaintextAdvContents<'d> {
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/tests.rs b/nearby/presence/np_adv/src/legacy/deserialize/tests.rs
index 5725e0b..3dfecd1 100644
--- a/nearby/presence/np_adv/src/legacy/deserialize/tests.rs
+++ b/nearby/presence/np_adv/src/legacy/deserialize/tests.rs
@@ -12,32 +12,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(unused_results, clippy::unwrap_used)]
+
extern crate alloc;
extern crate std;
use super::*;
-use crate::legacy::actions::{ActionBits, ActionsDataElement, Finder, NearbyShare};
-use crate::legacy::serialize::id_de_type_as_generic_de_type;
-use crate::shared_data::TxPower;
use crate::{
credential::{v0::V0, SimpleBroadcastCryptoMaterial},
de_type::IdentityDataElementType,
legacy::{
- actions,
+ actions::{self, ActionBits, ActionsDataElement, Finder, NearbyShare},
de_type::DeActualLength,
random_data_elements::{random_de_ciphertext, random_de_plaintext},
serialize::{
- encode_de_header_actual_len, AdvBuilder, DataElementBundle, Identity, LdtIdentity,
- ToDataElementBundle as _,
+ encode_de_header_actual_len, id_de_type_as_generic_de_type, AdvBuilder,
+ DataElementBundle, Identity, LdtIdentity, ToDataElementBundle,
},
PacketFlavorEnum, BLE_ADV_SVC_CONTENT_LEN,
},
- parse_adv_header, shared_data, AdvHeader, PublicIdentity,
+ parse_adv_header, shared_data,
+ shared_data::TxPower,
+ AdvHeader, PublicIdentity,
};
use alloc::vec::Vec;
use array_view::ArrayView;
use crypto_provider_default::CryptoProviderImpl;
-use init_with::InitWith as _;
use ldt_np_adv::LdtEncrypterXtsAes128;
use nom::error::{self, ErrorKind};
use rand_ext::rand::{prelude::SliceRandom, Rng as _};
@@ -357,7 +357,10 @@
#[test]
fn parse_encrypted_identity_contents_too_short_error() {
// 2 byte salt + 15 byte ciphertext: 1 too short
- let input = <[u8; 17]>::init_with_indices(|i| i as u8);
+ let mut input = [0u8; 17];
+ for (pos, e) in input.iter_mut().enumerate() {
+ *e = pos as u8
+ }
assert_eq!(
nom::Err::Error(error::Error { input: &input[2..], code: error::ErrorKind::TakeWhileMN }),
parse_encrypted_identity_de_contents(&input).unwrap_err()
@@ -367,7 +370,10 @@
#[test]
fn parse_encrypted_identity_contents_ok() {
// 2 byte salt + minimum 16 byte ciphertext
- let input = <[u8; 18]>::init_with_indices(|i| i as u8);
+ let mut input = [0u8; 18];
+ for (pos, e) in input.iter_mut().enumerate() {
+ *e = pos as u8
+ }
assert_eq!(
([].as_slice(), (ldt_np_adv::LegacySalt::from([0, 1]), &input[2..])),
parse_encrypted_identity_de_contents(&input).unwrap()
diff --git a/nearby/presence/np_adv/src/legacy/random_data_elements.rs b/nearby/presence/np_adv/src/legacy/random_data_elements.rs
index f416ffe..00a2e93 100644
--- a/nearby/presence/np_adv/src/legacy/random_data_elements.rs
+++ b/nearby/presence/np_adv/src/legacy/random_data_elements.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use crate::{
diff --git a/nearby/presence/np_adv/src/legacy/serialize/mod.rs b/nearby/presence/np_adv/src/legacy/serialize/mod.rs
index 2920b67..3746796 100644
--- a/nearby/presence/np_adv/src/legacy/serialize/mod.rs
+++ b/nearby/presence/np_adv/src/legacy/serialize/mod.rs
@@ -111,7 +111,7 @@
lazy_static::lazy_static! {
// Avoid either a panic-able code path or an error case that never happens by precalculating.
static ref PUBLIC_IDENTITY_DE_HEADER: u8 =
- encode_de_header_actual_len(DataElementType::PublicIdentity, DeActualLength::ZERO).unwrap();
+ encode_de_header_actual_len(DataElementType::PublicIdentity, DeActualLength::ZERO).expect("de length is in range");
}
impl Identity for PublicIdentity {
diff --git a/nearby/presence/np_adv/src/legacy/serialize/tests.rs b/nearby/presence/np_adv/src/legacy/serialize/tests.rs
index b4adc9f..7be30ba 100644
--- a/nearby/presence/np_adv/src/legacy/serialize/tests.rs
+++ b/nearby/presence/np_adv/src/legacy/serialize/tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
extern crate std;
use crate::legacy::actions::FastPairSass;
diff --git a/nearby/presence/np_adv/src/lib.rs b/nearby/presence/np_adv/src/lib.rs
index 1c42796..0b6d7ae 100644
--- a/nearby/presence/np_adv/src/lib.rs
+++ b/nearby/presence/np_adv/src/lib.rs
@@ -11,6 +11,7 @@
// 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.
+
//! Serialization and deserialization for v0 (legacy) and v1 (extended) Nearby Presence
//! advertisements.
//!
@@ -18,16 +19,13 @@
//! deserialization scenarios.
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(missing_docs)]
+#![allow(clippy::expect_used, clippy::indexing_slicing, clippy::panic)]
-#[cfg(any(test, feature = "alloc"))]
-extern crate alloc;
-extern crate core;
use crate::{
credential::{
- book::CredentialBook, v0::V0DiscoveryCryptoMaterial, v1::V1DiscoveryCryptoMaterial,
- DiscoveryCryptoMaterial, MatchedCredential, ProtocolVersion,
+ book::CredentialBook, v0::V0DiscoveryCryptoMaterial, v0::V0, v1::V1DiscoveryCryptoMaterial,
+ v1::V1, DiscoveryCryptoMaterial, MatchedCredential, ProtocolVersion,
+ ReferencedMatchedCredential,
},
deserialization_arena::ArenaOutOfSpace,
extended::deserialize::{
@@ -41,7 +39,10 @@
};
#[cfg(any(test, feature = "alloc"))]
+extern crate alloc;
+#[cfg(any(test, feature = "alloc"))]
use alloc::vec::Vec;
+
use array_vec::ArrayVecOption;
#[cfg(feature = "devtools")]
use array_view::ArrayView;
@@ -307,7 +308,7 @@
// By default, if we have an identity match, assume that decrypting the section worked,
// or that the section was somehow invalid.
// We don't care about maintaining order, so use O(1) remove
- self.encrypted_sections.swap_remove(i);
+ let _ = self.encrypted_sections.swap_remove(i);
// don't advance i -- it now points to a new element
}
}
@@ -564,6 +565,20 @@
fn metadata_key(&self) -> <Self::Version as ProtocolVersion>::MetadataKey;
}
+impl HasIdentityMatch for legacy::ShortMetadataKey {
+ type Version = V0;
+ fn metadata_key(&self) -> Self {
+ *self
+ }
+}
+
+impl HasIdentityMatch for MetadataKey {
+ type Version = V1;
+ fn metadata_key(&self) -> Self {
+ *self
+ }
+}
+
#[cfg(any(test, feature = "alloc"))]
/// Type for errors from [`WithMatchedCredential#decrypt_metadata`]
#[derive(Debug)]
@@ -589,10 +604,34 @@
metadata_nonce: [u8; 12],
contents: T,
}
+impl<'a, M: MatchedCredential + Clone, T: HasIdentityMatch>
+ WithMatchedCredential<ReferencedMatchedCredential<'a, M>, T>
+{
+ /// Clones the referenced match-data to update this container
+ /// so that the match-data is owned, rather than borrowed.
+ pub fn clone_match_data(self) -> WithMatchedCredential<M, T> {
+ let matched = self.matched.as_ref().clone();
+ let metadata_nonce = self.metadata_nonce;
+ let contents = self.contents;
+
+ WithMatchedCredential { matched, metadata_nonce, contents }
+ }
+}
impl<M: MatchedCredential, T: HasIdentityMatch> WithMatchedCredential<M, T> {
fn new(matched: M, metadata_nonce: [u8; 12], contents: T) -> Self {
Self { matched, metadata_nonce, contents }
}
+ /// Applies the given function to the wrapped contents, yielding
+ /// a new instance with the same matched-credential.
+ pub fn map<R: HasIdentityMatch>(
+ self,
+ mapping: impl FnOnce(T) -> R,
+ ) -> WithMatchedCredential<M, R> {
+ let contents = mapping(self.contents);
+ let matched = self.matched;
+ let metadata_nonce = self.metadata_nonce;
+ WithMatchedCredential { matched, metadata_nonce, contents }
+ }
/// Credential data for the credential that decrypted the content.
pub fn matched_credential(&self) -> &M {
&self.matched
diff --git a/nearby/presence/np_adv/tests/examples_v0.rs b/nearby/presence/np_adv/tests/examples_v0.rs
index 8310531..f7b7d5e 100644
--- a/nearby/presence/np_adv/tests/examples_v0.rs
+++ b/nearby/presence/np_adv/tests/examples_v0.rs
@@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::panic)]
+
use crypto_provider_default::CryptoProviderImpl;
use ldt_np_adv::*;
use np_adv::legacy::data_elements::TxPowerDataElement;
diff --git a/nearby/presence/np_adv/tests/examples_v1.rs b/nearby/presence/np_adv/tests/examples_v1.rs
index bf633e5..94b9d75 100644
--- a/nearby/presence/np_adv/tests/examples_v1.rs
+++ b/nearby/presence/np_adv/tests/examples_v1.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::panic)]
+
use crypto_provider::{CryptoProvider, CryptoRng};
use crypto_provider_default::CryptoProviderImpl;
use np_adv::extended::data_elements::TxPowerDataElement;
@@ -144,7 +146,7 @@
key_seed,
[0; 32], // Zeroing out MIC HMAC, since it's unused in examples here.
hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0),
- key_pair.public(),
+ key_pair.public().to_bytes(),
);
let credentials: [MatchableCredential<V1, MetadataMatchedCredential<_>>; 1] =
diff --git a/nearby/presence/np_adv_dynamic/Cargo.toml b/nearby/presence/np_adv_dynamic/Cargo.toml
new file mode 100644
index 0000000..74d6e3a
--- /dev/null
+++ b/nearby/presence/np_adv_dynamic/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "np_adv_dynamic"
+version.workspace = true
+edition.workspace = true
+publish.workspace = true
+
+[lints]
+workspace = true
+
+[dependencies]
+array_view.workspace = true
+np_adv = { workspace = true, features = ["alloc"] }
+crypto_provider.workspace = true
+thiserror.workspace = true
+sink.workspace = true
diff --git a/nearby/presence/np_adv_dynamic/src/extended.rs b/nearby/presence/np_adv_dynamic/src/extended.rs
new file mode 100644
index 0000000..f961bd6
--- /dev/null
+++ b/nearby/presence/np_adv_dynamic/src/extended.rs
@@ -0,0 +1,265 @@
+// 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::CryptoProvider;
+use np_adv::{extended::data_elements::*, extended::serialize::*, shared_data::*};
+use sink::Sink;
+use thiserror::Error;
+
+/// An advertisement builder for V1 advertisements where the
+/// presence/absence of salt is determined at run-time instead of compile-time.
+pub struct BoxedAdvBuilder {
+ adv_builder: AdvBuilder,
+}
+
+impl From<AdvBuilder> for BoxedAdvBuilder {
+ fn from(adv_builder: AdvBuilder) -> Self {
+ BoxedAdvBuilder { adv_builder }
+ }
+}
+
+/// Error possibly generated when attempting to add a section to
+/// a BoxedAdvBuilder.
+#[derive(Debug, Error)]
+pub enum BoxedAddSectionError {
+ /// An error which was generated by the underlying AdvBuilder wrapped by the BoxedAdvBuilder
+ #[error("{0}")]
+ Underlying(AddSectionError),
+ /// An error generated when the boxed advertisement builder is unsalted, but the section
+ /// identity requires salt.
+ #[error("Error generated when the BoxedAdvBuilder is unsalted, but the section identity requires salt.")]
+ IdentityRequiresSaltError,
+}
+
+impl From<AddSectionError> for BoxedAddSectionError {
+ fn from(wrapped: AddSectionError) -> Self {
+ BoxedAddSectionError::Underlying(wrapped)
+ }
+}
+
+fn wrap_section_builder<'a, C: CryptoProvider, S: Into<BoxedSectionBuilder<'a, C>>>(
+ maybe_section_builder: Result<S, AddSectionError>,
+) -> Result<BoxedSectionBuilder<'a, C>, BoxedAddSectionError> {
+ let section_builder = maybe_section_builder?;
+ Ok(section_builder.into())
+}
+
+impl BoxedAdvBuilder {
+ /// Create a section builder using the given identity.
+ ///
+ /// Returns `Err` if the underlying advertisement builder
+ /// yields an error when attempting to add a new section
+ /// (typically because there's no more available adv space),
+ /// or if the requested identity requires salt, and the
+ /// advertisement builder is salt-less.
+ pub fn section_builder<C: CryptoProvider>(
+ &mut self,
+ identity: BoxedIdentity<C>,
+ ) -> Result<BoxedSectionBuilder<C>, BoxedAddSectionError> {
+ match identity {
+ BoxedIdentity::PublicIdentity => wrap_section_builder(
+ self.adv_builder.section_builder(PublicSectionEncoder::default()),
+ ),
+ BoxedIdentity::MicEncrypted(ident) => {
+ wrap_section_builder(self.adv_builder.section_builder(ident))
+ }
+ BoxedIdentity::SignedEncrypted(ident) => {
+ wrap_section_builder(self.adv_builder.section_builder(ident))
+ }
+ }
+ }
+
+ /// Convert the builder into an encoded advertisement.
+ pub fn into_advertisement(self) -> EncodedAdvertisement {
+ self.adv_builder.into_advertisement()
+ }
+}
+
+/// A wrapped v1 identity whose type is given at run-time.
+pub enum BoxedIdentity<C: CryptoProvider> {
+ /// Public identity.
+ PublicIdentity,
+ /// An encrypted identity leveraging MIC for verification.
+ MicEncrypted(MicEncryptedSectionEncoder<C>),
+ /// An encrypted identity leveraging signatures for verification.
+ SignedEncrypted(SignedEncryptedSectionEncoder<C>),
+}
+
+/// A `SectionBuilder` whose corresponding Identity
+/// and salted-ness is given at run-time instead of
+/// at compile-time.
+pub enum BoxedSectionBuilder<'a, C: CryptoProvider> {
+ /// A builder for a public section.
+ Public(SectionBuilder<'a, PublicSectionEncoder>),
+ /// A builder for a MIC-verified section.
+ MicEncrypted(SectionBuilder<'a, MicEncryptedSectionEncoder<C>>),
+ /// A builder for a signature-verified section.
+ SignedEncrypted(SectionBuilder<'a, SignedEncryptedSectionEncoder<C>>),
+}
+
+impl<'a, C: CryptoProvider> BoxedSectionBuilder<'a, C> {
+ /// Returns true if this wraps a section builder which
+ /// leverages some encrypted identity.
+ pub fn is_encrypted(&self) -> bool {
+ match self {
+ BoxedSectionBuilder::Public(_) => false,
+ BoxedSectionBuilder::MicEncrypted(_) => true,
+ BoxedSectionBuilder::SignedEncrypted(_) => true,
+ }
+ }
+ /// Add this builder to the advertisement that created it.
+ pub fn add_to_advertisement(self) {
+ match self {
+ BoxedSectionBuilder::Public(x) => x.add_to_advertisement(),
+ BoxedSectionBuilder::MicEncrypted(x) => x.add_to_advertisement(),
+ BoxedSectionBuilder::SignedEncrypted(x) => x.add_to_advertisement(),
+ }
+ }
+ /// Add a data element to the section with a closure that returns a `Result`.
+ ///
+ /// The provided `build_de` closure will be invoked with the derived salt for this DE,
+ /// if any salt has been specified for the surrounding advertisement.
+ pub fn add_de_res<E>(
+ &mut self,
+ build_de: impl FnOnce(Option<DeSalt<C>>) -> Result<BoxedWriteDataElement, E>,
+ ) -> Result<(), AddDataElementError<E>> {
+ match self {
+ BoxedSectionBuilder::Public(x) => {
+ let build_de_modified = |()| build_de(None);
+ x.add_de_res(build_de_modified)
+ }
+ BoxedSectionBuilder::MicEncrypted(x) => {
+ let build_de_modified = |de_salt: DeSalt<C>| build_de(Some(de_salt));
+ x.add_de_res(build_de_modified)
+ }
+ BoxedSectionBuilder::SignedEncrypted(x) => {
+ let build_de_modified = |de_salt: DeSalt<C>| build_de(Some(de_salt));
+ x.add_de_res(build_de_modified)
+ }
+ }
+ }
+ /// Like add_de_res, but for infalliable closures
+ pub fn add_de(
+ &mut self,
+ build_de: impl FnOnce(Option<DeSalt<C>>) -> BoxedWriteDataElement,
+ ) -> Result<(), AddDataElementError<()>> {
+ self.add_de_res(|derived_salt| Ok::<_, ()>(build_de(derived_salt)))
+ }
+}
+
+impl<'a, C: CryptoProvider> From<SectionBuilder<'a, PublicSectionEncoder>>
+ for BoxedSectionBuilder<'a, C>
+{
+ fn from(section_builder: SectionBuilder<'a, PublicSectionEncoder>) -> Self {
+ BoxedSectionBuilder::Public(section_builder)
+ }
+}
+
+impl<'a, C: CryptoProvider> From<SectionBuilder<'a, MicEncryptedSectionEncoder<C>>>
+ for BoxedSectionBuilder<'a, C>
+{
+ fn from(section_builder: SectionBuilder<'a, MicEncryptedSectionEncoder<C>>) -> Self {
+ BoxedSectionBuilder::MicEncrypted(section_builder)
+ }
+}
+
+impl<'a, C: CryptoProvider> From<SectionBuilder<'a, SignedEncryptedSectionEncoder<C>>>
+ for BoxedSectionBuilder<'a, C>
+{
+ fn from(section_builder: SectionBuilder<'a, SignedEncryptedSectionEncoder<C>>) -> Self {
+ BoxedSectionBuilder::SignedEncrypted(section_builder)
+ }
+}
+
+/// Mutable trait object reference to a `Sink<u8>`
+pub struct DynSink<'a> {
+ wrapped: &'a mut dyn Sink<u8>,
+}
+
+impl<'a> Sink<u8> for DynSink<'a> {
+ fn try_extend_from_slice(&mut self, items: &[u8]) -> Option<()> {
+ self.wrapped.try_extend_from_slice(items)
+ }
+ fn try_push(&mut self, item: u8) -> Option<()> {
+ self.wrapped.try_push(item)
+ }
+}
+
+impl<'a> From<&'a mut dyn Sink<u8>> for DynSink<'a> {
+ fn from(wrapped: &'a mut dyn Sink<u8>) -> Self {
+ DynSink { wrapped }
+ }
+}
+
+/// A version of the WriteDataElement trait which is object-safe
+pub trait DynWriteDataElement {
+ /// Gets the data-element header for the data element
+ fn de_header(&self) -> DeHeader;
+ /// Writes the contents of the DE payload to the given DynSink.
+ /// Returns Some(()) if the write operation was successful,
+ /// and None if it was unsuccessful
+ fn write_de_contents(&self, sink: DynSink) -> Option<()>;
+}
+
+impl<T: WriteDataElement> DynWriteDataElement for T {
+ fn de_header(&self) -> DeHeader {
+ WriteDataElement::de_header(self)
+ }
+ fn write_de_contents(&self, mut sink: DynSink) -> Option<()> {
+ WriteDataElement::write_de_contents(self, &mut sink)
+ }
+}
+
+/// Trait object wrapper for DynWriteDataElement instances
+pub struct BoxedWriteDataElement {
+ wrapped: Box<dyn DynWriteDataElement>,
+}
+
+impl BoxedWriteDataElement {
+ /// Constructs a new `BoxedWriteDataElement` from a `WriteDataElement`
+ /// whose trait impl is valid for a `'static` lifetime.
+ pub fn new<D: WriteDataElement + 'static>(wrapped: D) -> Self {
+ let wrapped = Box::new(wrapped);
+ Self { wrapped }
+ }
+}
+
+impl WriteDataElement for BoxedWriteDataElement {
+ fn de_header(&self) -> DeHeader {
+ self.wrapped.de_header()
+ }
+ fn write_de_contents<S: Sink<u8>>(&self, sink: &mut S) -> Option<()> {
+ let sink: &mut dyn Sink<u8> = sink;
+ let dyn_sink = DynSink::from(sink);
+ self.wrapped.write_de_contents(dyn_sink)
+ }
+}
+
+impl From<TxPower> for BoxedWriteDataElement {
+ fn from(tx_power: TxPower) -> Self {
+ BoxedWriteDataElement::new::<TxPowerDataElement>(tx_power.into())
+ }
+}
+
+impl From<ContextSyncSeqNum> for BoxedWriteDataElement {
+ fn from(context_sync_sequence_num: ContextSyncSeqNum) -> Self {
+ BoxedWriteDataElement::new::<ContextSyncSeqNumDataElement>(context_sync_sequence_num.into())
+ }
+}
+
+impl From<ActionsDataElement> for BoxedWriteDataElement {
+ fn from(data: ActionsDataElement) -> Self {
+ BoxedWriteDataElement::new(data)
+ }
+}
diff --git a/nearby/presence/np_adv_dynamic/src/legacy.rs b/nearby/presence/np_adv_dynamic/src/legacy.rs
new file mode 100644
index 0000000..191ef75
--- /dev/null
+++ b/nearby/presence/np_adv_dynamic/src/legacy.rs
@@ -0,0 +1,349 @@
+// 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 array_view::ArrayView;
+use crypto_provider::CryptoProvider;
+use np_adv::legacy::actions::*;
+use np_adv::legacy::data_elements::*;
+use np_adv::legacy::serialize::*;
+use np_adv::legacy::*;
+use np_adv::shared_data::*;
+use np_adv::PublicIdentity;
+use thiserror::Error;
+
+/// Wrapper around a V0 advertisement builder which
+/// is agnostic to the kind of identity used in the advertisement.
+/// Instead of compile-time errors for non-matching packet flavors,
+/// this builder instead defers any generated errors to run-time.
+/// Generic over the Aes algorithm used for any encrypted identities,
+/// since that is generally specified at compile-time.
+pub enum BoxedAdvBuilder<C: CryptoProvider> {
+ /// Builder for public advertisements.
+ Public(AdvBuilder<PublicIdentity>),
+ /// Builder for LDT-encryptedadvertisements.
+ Ldt(AdvBuilder<LdtIdentity<C>>),
+}
+
+/// Wrapper around possible errors which occur only during
+/// advertisement construction from a builder.
+#[derive(Debug)]
+pub enum BoxedAdvConstructionError {
+ /// An error originating from a problem with LDT
+ /// encryption of the advertisement contents.
+ Ldt(LdtPostprocessError),
+}
+
+impl<C: CryptoProvider> BoxedAdvBuilder<C> {
+ /// Returns true if this wraps an adv builder which
+ /// leverages some encrypted identity.
+ pub fn is_encrypted(&self) -> bool {
+ match self {
+ BoxedAdvBuilder::Public(_) => false,
+ BoxedAdvBuilder::Ldt(_) => true,
+ }
+ }
+ /// Constructs a new BoxedAdvBuilder from the given BoxedIdentity
+ pub fn new(identity: BoxedIdentity<C>) -> Self {
+ match identity {
+ BoxedIdentity::Public(identity) => BoxedAdvBuilder::Public(AdvBuilder::new(identity)),
+ BoxedIdentity::LdtIdentity(identity) => BoxedAdvBuilder::Ldt(AdvBuilder::new(identity)),
+ }
+ }
+ /// Attempts to add a data element to the advertisement
+ /// being built by this BoxedAdvBuilder. Returns
+ /// nothing if successful, and a BoxedAddDataElementError
+ /// if something went wrong in the attempt to add the DE.
+ pub fn add_data_element(
+ &mut self,
+ data_element: ToBoxedDataElementBundle,
+ ) -> Result<(), BoxedAddDataElementError> {
+ match self {
+ BoxedAdvBuilder::Public(public_builder) => {
+ //Verify that we can get the data element as plaintext
+ let maybe_plaintext_data_element = data_element.to_plaintext();
+ match maybe_plaintext_data_element {
+ Some(plaintext_data_element) => public_builder
+ .add_data_element(plaintext_data_element)
+ .map_err(|e| e.into()),
+ None => Err(BoxedAddDataElementError::FlavorMismatchError),
+ }
+ }
+ BoxedAdvBuilder::Ldt(private_builder) => {
+ //Verify that we can get the data element as ciphertext
+ let maybe_ciphertext_data_element = data_element.to_ciphertext();
+ match maybe_ciphertext_data_element {
+ Some(ciphertext_data_element) => private_builder
+ .add_data_element(ciphertext_data_element)
+ .map_err(|e| e.into()),
+ None => Err(BoxedAddDataElementError::FlavorMismatchError),
+ }
+ }
+ }
+ }
+ /// Consume this BoxedAdvBuilder and attempt to create
+ /// a serialized advertisement including the added DEs.
+ pub fn into_advertisement(
+ self,
+ ) -> Result<ArrayView<u8, BLE_ADV_SVC_CONTENT_LEN>, BoxedAdvConstructionError> {
+ match self {
+ BoxedAdvBuilder::Public(x) => {
+ match x.into_advertisement() {
+ Ok(x) => Ok(x),
+ Err(x) => match x {}, //Infallible
+ }
+ }
+ BoxedAdvBuilder::Ldt(x) => {
+ x.into_advertisement().map_err(BoxedAdvConstructionError::Ldt)
+ }
+ }
+ }
+}
+
+/// Possible errors generated when trying to add a DE to a
+/// BoxedAdvBuilder.
+#[derive(Debug, Error)]
+pub enum BoxedAddDataElementError {
+ /// Some kind of error in adding the data element which
+ /// is not an issue with trying to add a DE of the incorrect
+ /// packet flavoring.
+ #[error("{0:?}")]
+ UnderlyingError(AddDataElementError),
+ #[error(
+ "Expected packet flavoring for added DEs does not match the actual packet flavor of the DE"
+ )]
+ /// Error when attempting to add a DE which requires one
+ /// of an (encrypted/plaintext) advertisement, but the
+ /// advertisement builder doesn't match this requirement.
+ FlavorMismatchError,
+}
+
+impl From<AddDataElementError> for BoxedAddDataElementError {
+ fn from(add_data_element_error: AddDataElementError) -> Self {
+ BoxedAddDataElementError::UnderlyingError(add_data_element_error)
+ }
+}
+
+/// Trait object reference to a `ToDataElementBundle<I>` with lifetime `'a`.
+/// Implements `ToDataElementBundle<I>` by deferring to the wrapped trait object.
+pub struct DynamicToDataElementBundle<'a, I: PacketFlavor> {
+ wrapped: &'a dyn ToDataElementBundle<I>,
+}
+
+impl<'a, I: PacketFlavor> From<&'a dyn ToDataElementBundle<I>>
+ for DynamicToDataElementBundle<'a, I>
+{
+ fn from(wrapped: &'a dyn ToDataElementBundle<I>) -> Self {
+ DynamicToDataElementBundle { wrapped }
+ }
+}
+
+impl<'a, I: PacketFlavor> ToDataElementBundle<I> for DynamicToDataElementBundle<'a, I> {
+ fn to_de_bundle(&self) -> DataElementBundle<I> {
+ self.wrapped.to_de_bundle()
+ }
+}
+
+/// Trait for types which can provide trait object
+/// references to either plaintext or ciphertext [ToDataElementBundle]
+pub trait ToMultiFlavorElementBundle {
+ /// Gets the associated trait object reference to a `ToDataElementBundle<Plaintext>`
+ /// with the same lifetime as a reference to the implementor.
+ fn to_plaintext(&self) -> DynamicToDataElementBundle<Plaintext>;
+
+ /// Gets the associated trait object reference to a `ToDataElementBundle<Ciphertext>`
+ /// with the same lifetime as a reference to the implementor.
+ fn to_ciphertext(&self) -> DynamicToDataElementBundle<Ciphertext>;
+}
+
+/// Blanket impl of [ToMultiFlavorElementBundle] for implementors of [ToDataElementBundle]
+/// for both [Plaintext] and [Ciphertext] packet flavors.
+impl<T: ToDataElementBundle<Plaintext> + ToDataElementBundle<Ciphertext>> ToMultiFlavorElementBundle
+ for T
+{
+ fn to_plaintext(&self) -> DynamicToDataElementBundle<Plaintext> {
+ let reference: &dyn ToDataElementBundle<Plaintext> = self;
+ reference.into()
+ }
+ fn to_ciphertext(&self) -> DynamicToDataElementBundle<Ciphertext> {
+ let reference: &dyn ToDataElementBundle<Ciphertext> = self;
+ reference.into()
+ }
+}
+
+/// Boxed trait object version of [ToDataElementBundle] which incorporates
+/// all possible variants on generatable packet flavoring
+/// (`Plaintext`, `Ciphertext`, or both, as a [ToMultiFlavorElementBundle])
+pub enum ToBoxedDataElementBundle {
+ /// The underlying DE is plaintext-only.
+ Plaintext(Box<dyn ToDataElementBundle<Plaintext>>),
+ /// The underlying DE is ciphertext-only.
+ Ciphertext(Box<dyn ToDataElementBundle<Ciphertext>>),
+ /// The underlying DE may exist in plaintext or
+ /// in ciphertext advertisements.
+ Both(Box<dyn ToMultiFlavorElementBundle>),
+}
+
+impl ToBoxedDataElementBundle {
+ /// If this [ToBoxedDataElementBundle] can generate plaintext, returns
+ /// a trait object reference to a `ToDataElementBundle<Plaintext>`
+ pub fn to_plaintext(&self) -> Option<DynamicToDataElementBundle<Plaintext>> {
+ match &self {
+ ToBoxedDataElementBundle::Plaintext(x) => Some(x.as_ref().into()),
+ ToBoxedDataElementBundle::Ciphertext(_) => None,
+ ToBoxedDataElementBundle::Both(x) => Some(x.as_ref().to_plaintext()),
+ }
+ }
+ /// If this [ToBoxedDataElementBundle] can generate ciphertext, returns
+ /// a trait object reference to a `ToDataElementBundle<Ciphertext>`
+ pub fn to_ciphertext(&self) -> Option<DynamicToDataElementBundle<Ciphertext>> {
+ match &self {
+ ToBoxedDataElementBundle::Plaintext(_) => None,
+ ToBoxedDataElementBundle::Ciphertext(x) => Some(x.as_ref().into()),
+ ToBoxedDataElementBundle::Both(x) => Some(x.as_ref().to_ciphertext()),
+ }
+ }
+}
+
+/// Boxed version of implementors of the Identity trait.
+/// A is the underlying Aes algorithm leveraged by ciphertext-based identities.
+pub enum BoxedIdentity<C: CryptoProvider> {
+ /// Public Identity.
+ Public(PublicIdentity),
+ /// An encrypted identity, using LDT encryption.
+ LdtIdentity(LdtIdentity<C>),
+}
+
+impl<C: CryptoProvider> From<PublicIdentity> for BoxedIdentity<C> {
+ fn from(public_identity: PublicIdentity) -> BoxedIdentity<C> {
+ BoxedIdentity::Public(public_identity)
+ }
+}
+
+impl<C: CryptoProvider> From<LdtIdentity<C>> for BoxedIdentity<C> {
+ fn from(ldt_identity: LdtIdentity<C>) -> BoxedIdentity<C> {
+ BoxedIdentity::LdtIdentity(ldt_identity)
+ }
+}
+
+impl From<TxPower> for ToBoxedDataElementBundle {
+ fn from(data: TxPower) -> Self {
+ ToBoxedDataElementBundle::Both(Box::new(TxPowerDataElement::from(data)))
+ }
+}
+
+impl From<BoxedActionBits> for ToBoxedDataElementBundle {
+ fn from(action_bits: BoxedActionBits) -> Self {
+ match action_bits {
+ BoxedActionBits::Plaintext(action_bits) => {
+ ToBoxedDataElementBundle::Plaintext(Box::new(ActionsDataElement::from(action_bits)))
+ }
+ BoxedActionBits::Ciphertext(action_bits) => ToBoxedDataElementBundle::Ciphertext(
+ Box::new(ActionsDataElement::from(action_bits)),
+ ),
+ }
+ }
+}
+
+/// Boxed version of `ToActionElement` which allows abstracting over
+/// what packet flavors are supported by a given action.
+pub enum ToBoxedActionElement {
+ /// A context-sync sequence number.
+ ContextSyncSeqNum(ContextSyncSeqNum),
+ /// Action bit for active unlock.
+ ActiveUnlock(bool),
+ /// Action bit for nearby share.
+ NearbyShare(bool),
+ /// Action bit for instant tethering.
+ InstantTethering(bool),
+ /// Action bit for PhoneHub.
+ PhoneHub(bool),
+ /// Action bit for Finder.
+ Finder(bool),
+ /// Action bit for Fast Pair/SASS
+ FastPairSass(bool),
+ /// Action bit for Presence Manager.
+ PresenceManager(bool),
+}
+
+/// [`ActionBits`] with runtime-determined packet flavoring
+pub enum BoxedActionBits {
+ /// Action-bits for a plaintext advertisement.
+ Plaintext(ActionBits<Plaintext>),
+ /// Action-bits for a ciphertext advertisement.
+ Ciphertext(ActionBits<Ciphertext>),
+}
+
+/// Error which is raised when the flavor of a [`BoxedActionBits`]
+/// does not match the supported flavors of a [`ToBoxedActionElement`]
+/// upon attempting to add the action to the bit-field.
+#[derive(Debug)]
+pub struct BoxedSetActionFlavorError;
+
+impl BoxedActionBits {
+ /// Constructs the [`BoxedActionBits`] variant with the specified packet
+ /// flavor variant, and no bits set.
+ pub fn new(packet_flavor: PacketFlavorEnum) -> Self {
+ match packet_flavor {
+ PacketFlavorEnum::Plaintext => BoxedActionBits::Plaintext(ActionBits::default()),
+ PacketFlavorEnum::Ciphertext => BoxedActionBits::Ciphertext(ActionBits::default()),
+ }
+ }
+
+ fn set<F: PacketFlavor, E: ToActionElement<F>>(
+ action_bits: &mut ActionBits<F>,
+ to_element: E,
+ ) -> Result<(), BoxedSetActionFlavorError> {
+ action_bits.set_action(to_element);
+ Ok(())
+ }
+
+ /// Attempts to set the specified [`ToBoxedActionElement`], yielding
+ /// a [`BoxedSetActionFlavorError`] if the flavor of this
+ /// [`BoxedActionBits`] isn't supported by the passed [`ToBoxedActionElement`].
+ pub fn set_action(
+ &mut self,
+ to_element: ToBoxedActionElement,
+ ) -> Result<(), BoxedSetActionFlavorError> {
+ match self {
+ BoxedActionBits::Plaintext(action_bits) => match to_element {
+ ToBoxedActionElement::ContextSyncSeqNum(x) => Self::set(action_bits, x),
+ ToBoxedActionElement::NearbyShare(b) => {
+ Self::set(action_bits, NearbyShare::from(b))
+ }
+ ToBoxedActionElement::Finder(b) => Self::set(action_bits, Finder::from(b)),
+ ToBoxedActionElement::FastPairSass(b) => {
+ Self::set(action_bits, FastPairSass::from(b))
+ }
+ _ => Err(BoxedSetActionFlavorError),
+ },
+ BoxedActionBits::Ciphertext(action_bits) => match to_element {
+ ToBoxedActionElement::ContextSyncSeqNum(x) => Self::set(action_bits, x),
+ ToBoxedActionElement::ActiveUnlock(b) => {
+ Self::set(action_bits, ActiveUnlock::from(b))
+ }
+ ToBoxedActionElement::NearbyShare(b) => {
+ Self::set(action_bits, NearbyShare::from(b))
+ }
+ ToBoxedActionElement::InstantTethering(b) => {
+ Self::set(action_bits, InstantTethering::from(b))
+ }
+ ToBoxedActionElement::PhoneHub(b) => Self::set(action_bits, PhoneHub::from(b)),
+ ToBoxedActionElement::PresenceManager(b) => {
+ Self::set(action_bits, PresenceManager::from(b))
+ }
+ _ => Err(BoxedSetActionFlavorError),
+ },
+ }
+ }
+}
diff --git a/nearby/presence/np_adv_dynamic/src/lib.rs b/nearby/presence/np_adv_dynamic/src/lib.rs
new file mode 100644
index 0000000..4ba8f8b
--- /dev/null
+++ b/nearby/presence/np_adv_dynamic/src/lib.rs
@@ -0,0 +1,21 @@
+// 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.
+
+//! A no_std-friendly wrapper around `np_adv` to allow dynamic-style
+//! advertisement serialization, with correctness checked at run-time.
+
+/// Dynamic wrappers around extended adv serialization.
+pub mod extended;
+/// Dynamic wrappers around legacy adv serialization.
+pub mod legacy;
diff --git a/nearby/presence/np_c_ffi/Cargo.lock b/nearby/presence/np_c_ffi/Cargo.lock
index 796292b..836d35b 100644
--- a/nearby/presence/np_c_ffi/Cargo.lock
+++ b/nearby/presence/np_c_ffi/Cargo.lock
@@ -668,8 +668,10 @@
"crypto_provider_default",
"handle_map",
"lazy_static",
+ "ldt_np_adv",
"lock_adapter",
"np_adv",
+ "np_hkdf",
]
[[package]]
diff --git a/nearby/presence/np_c_ffi/include/c/np_c_ffi.h b/nearby/presence/np_c_ffi/include/c/np_c_ffi.h
index 03e5821..81914c9 100644
--- a/nearby/presence/np_c_ffi/include/c/np_c_ffi.h
+++ b/nearby/presence/np_c_ffi/include/c/np_c_ffi.h
@@ -33,6 +33,21 @@
#include <stdlib.h>
/**
+ * Result type for trying to add a credential to a credential-slab.
+ */
+enum np_ffi_AddCredentialToSlabResult {
+ /**
+ * We succeeded in adding the credential to the slab.
+ */
+ NP_FFI_ADD_CREDENTIAL_TO_SLAB_RESULT_SUCCESS = 0,
+ /**
+ * The handle to the slab was actually invalid.
+ */
+ NP_FFI_ADD_CREDENTIAL_TO_SLAB_RESULT_INVALID_HANDLE = 1,
+};
+typedef uint8_t np_ffi_AddCredentialToSlabResult;
+
+/**
* The possible boolean action types which can be present in an Actions data element
*/
enum np_ffi_BooleanActionType {
@@ -51,19 +66,41 @@
*/
enum np_ffi_CreateCredentialBookResultKind {
/**
- * There was no space left to create a new credential book
- */
- NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_NO_SPACE_LEFT = 0,
- /**
* We created a new credential book behind the given handle.
* The associated payload may be obtained via
* `CreateCredentialBookResult#into_success()`.
*/
- NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_SUCCESS = 1,
+ NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_SUCCESS = 0,
+ /**
+ * There was no space left to create a new credential book
+ */
+ NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_NO_SPACE_LEFT = 1,
+ /**
+ * The slab that we tried to create a credential-book from
+ * actually was an invalid handle.
+ */
+ NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_INVALID_SLAB_HANDLE = 2,
};
typedef uint8_t np_ffi_CreateCredentialBookResultKind;
/**
+ * Discriminant for `CreateCredentialSlabResult`
+ */
+enum np_ffi_CreateCredentialSlabResultKind {
+ /**
+ * There was no space left to create a new credential slab
+ */
+ NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_KIND_NO_SPACE_LEFT = 0,
+ /**
+ * We created a new credential slab behind the given handle.
+ * The associated payload may be obtained via
+ * `CreateCredentialSlabResult#into_success()`.
+ */
+ NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_KIND_SUCCESS = 1,
+};
+typedef uint8_t np_ffi_CreateCredentialSlabResultKind;
+
+/**
* A result-type enum which tells the caller whether/not a deallocation
* succeeded or failed due to the requested handle not being present.
*/
@@ -122,16 +159,8 @@
typedef uint8_t np_ffi_DeserializedV0AdvertisementKind;
/**
- * Represents deserialized information about the V0 identity utilized
- * by a deserialized V0 advertisement
- */
-typedef enum {
- NP_FFI_DESERIALIZED_V0_IDENTITY_PLAINTEXT,
- NP_FFI_DESERIALIZED_V0_IDENTITY_DECRYPTED,
-} np_ffi_DeserializedV0Identity;
-
-/**
- * Discriminant for `DeserializedV0Identity`.
+ * Discriminant for deserialized information about the V0
+ * identity utilized by a deserialized V0 advertisement.
*/
enum np_ffi_DeserializedV0IdentityKind {
/**
@@ -277,8 +306,9 @@
* Result type for `create_credential_book`
*/
enum np_ffi_CreateCredentialBookResult_Tag {
- NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_NO_SPACE_LEFT = 0,
- NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_SUCCESS = 1,
+ NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_SUCCESS = 0,
+ NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_NO_SPACE_LEFT = 1,
+ NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_INVALID_SLAB_HANDLE = 2,
};
typedef uint8_t np_ffi_CreateCredentialBookResult_Tag;
@@ -291,6 +321,79 @@
} np_ffi_CreateCredentialBookResult;
/**
+ *A `#[repr(C)]` handle to a value of type `super::CredentialSlabInternals`.
+ */
+typedef struct {
+ uint64_t handle_id;
+} np_ffi_CredentialSlab;
+
+/**
+ * Result type for `create_credential_slab`
+ */
+typedef enum {
+ NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_NO_SPACE_LEFT,
+ NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_SUCCESS,
+} np_ffi_CreateCredentialSlabResult_Tag;
+
+typedef struct {
+ np_ffi_CreateCredentialSlabResult_Tag tag;
+ union {
+ struct {
+ np_ffi_CredentialSlab success;
+ };
+ };
+} np_ffi_CreateCredentialSlabResult;
+
+/**
+ * Cryptographic information about a particular V0 discovery credential
+ * necessary to match and decrypt encrypted V0 advertisements.
+ */
+typedef struct {
+ uint8_t key_seed[32];
+ uint8_t legacy_metadata_key_hmac[32];
+} np_ffi_V0DiscoveryCredential;
+
+/**
+ * A representation of a MatchedCredential which is passable across the FFI boundary
+ */
+typedef struct {
+ uint32_t cred_id;
+ const uint8_t *encrypted_metadata_bytes_buffer;
+ uintptr_t encrypted_metadata_bytes_len;
+} np_ffi_FfiMatchedCredential;
+
+/**
+ * Representation of a V0 credential that contains additional data to provide back to caller once it
+ * is matched. The credential_id can be used by the caller to correlate it back to the full
+ * credentials details.
+ */
+typedef struct {
+ np_ffi_V0DiscoveryCredential discovery_cred;
+ np_ffi_FfiMatchedCredential matched_cred;
+} np_ffi_V0MatchableCredential;
+
+/**
+ * Cryptographic information about a particular V1 discovery credential
+ * necessary to match and decrypt encrypted V1 advertisement sections.
+ */
+typedef struct {
+ uint8_t key_seed[32];
+ uint8_t expected_unsigned_metadata_key_hmac[32];
+ uint8_t expected_signed_metadata_key_hmac[32];
+ uint8_t pub_key[32];
+} np_ffi_V1DiscoveryCredential;
+
+/**
+ * Representation of a V1 credential that contains additional data to provide back to caller once it
+ * is matched. The credential_id can be used by the caller to correlate it back to the full
+ * credentials details.
+ */
+typedef struct {
+ np_ffi_V1DiscoveryCredential discovery_cred;
+ np_ffi_FfiMatchedCredential matched_cred;
+} np_ffi_V1MatchableCredential;
+
+/**
*A `#[repr(C)]` handle to a value of type `super::V0PayloadInternals`.
*/
typedef struct {
@@ -303,7 +406,7 @@
typedef struct {
uint8_t num_des;
np_ffi_V0Payload payload;
- np_ffi_DeserializedV0Identity identity;
+ np_ffi_DeserializedV0IdentityKind identity_kind;
} np_ffi_LegibleDeserializedV0Advertisement;
/**
@@ -527,6 +630,10 @@
*/
typedef struct {
/**
+ * The offset of this generic data-element.
+ */
+ uint8_t offset;
+ /**
* The DE type code of this generic data-element.
*/
np_ffi_V1DEType de_type;
@@ -616,6 +723,22 @@
void np_ffi_global_config_set_num_shards(uint8_t num_shards);
/**
+ * Sets the maximum number of active handles to credential slabs
+ * which may be active at any one time.
+ * Default value: Max value.
+ * Max value: `u32::MAX - 1`.
+ *
+ * Useful for bounding the maximum memory used by the client application
+ * on credential slabs in constrained-memory environments.
+ *
+ * Setting this value will have no effect if the handle-maps for the
+ * API have already begun being used by the client code, and any
+ * values set will take effect upon the first usage of any API
+ * call utilizing credential slabs.
+ */
+void np_ffi_global_config_set_max_num_credential_slabs(uint32_t max_num_credential_slabs);
+
+/**
* Sets the maximum number of active handles to credential books
* which may be active at any one time.
* Default value: Max value.
@@ -666,9 +789,10 @@
void np_ffi_global_config_set_max_num_deserialized_v1_advertisements(uint32_t max_num_deserialized_v1_advertisements);
/**
- * Allocates a new credential-book, returning a handle to the created object
+ * Allocates a new credential-book from the given slab, returning a handle
+ * to the created object. The slab will be deallocated by this call.
*/
-np_ffi_CreateCredentialBookResult np_ffi_create_credential_book(void);
+np_ffi_CreateCredentialBookResult np_ffi_create_credential_book_from_slab(np_ffi_CredentialSlab slab);
/**
* Gets the tag of a `CreateCredentialBookResult` tagged enum.
@@ -682,11 +806,54 @@
np_ffi_CredentialBook np_ffi_CreateCredentialBookResult_into_SUCCESS(np_ffi_CreateCredentialBookResult result);
/**
+ * Deallocates a credential-slab by its handle.
+ */
+np_ffi_DeallocateResult np_ffi_deallocate_credential_slab(np_ffi_CredentialSlab credential_slab);
+
+/**
* Deallocates a credential-book by its handle
*/
np_ffi_DeallocateResult np_ffi_deallocate_credential_book(np_ffi_CredentialBook credential_book);
/**
+ * Allocates a new credential-slab, returning a handle to the created object
+ */
+np_ffi_CreateCredentialSlabResult np_ffi_create_credential_slab(void);
+
+/**
+ * Gets the tag of a `CreateCredentialSlabResult` tagged enum.
+ */
+np_ffi_CreateCredentialSlabResultKind np_ffi_CreateCredentialSlabResult_kind(np_ffi_CreateCredentialSlabResult result);
+
+/**
+ * Casts a `CreateCredentialSlabResult` to the `SUCCESS` variant, panicking in the
+ * case where the passed value is of a different enum variant.
+ */
+np_ffi_CredentialSlab np_ffi_CreateCredentialSlabResult_into_SUCCESS(np_ffi_CreateCredentialSlabResult result);
+
+/**
+ * Adds the given V0 discovery credential with some associated
+ * match-data to this credential slab.
+ *
+ * Safety: this is safe if the provided pointer points to a valid memory address
+ * which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
+ * so concurrent modification of the array from another thread would cause undefined behavior.
+ */
+np_ffi_AddCredentialToSlabResult np_ffi_CredentialSlab_add_v0_credential(np_ffi_CredentialSlab credential_slab,
+ np_ffi_V0MatchableCredential v0_cred);
+
+/**
+ * Adds the given V1 discovery credential with some associated
+ * match-data to this credential slab.
+ *
+ * Safety: this is safe if the provided pointer points to a valid memory address
+ * which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
+ * so concurrent modification of the array from another thread would cause undefined behavior.
+ */
+np_ffi_AddCredentialToSlabResult np_ffi_CredentialSlab_add_v1_credential(np_ffi_CredentialSlab credential_slab,
+ np_ffi_V1MatchableCredential v1_cred);
+
+/**
* Attempts to deserialize an advertisement with the given service-data
* payload (presumed to be under the NP service UUID) using credentials
* pulled from the given credential-book.
@@ -751,9 +918,9 @@
np_ffi_V0Payload np_ffi_LegibleDeserializedV0Advertisement_into_payload(np_ffi_LegibleDeserializedV0Advertisement adv);
/**
- * Gets just the identity information associated with a `LegibleDeserializedV0Advertisement`.
+ * Gets just the identity kind associated with a `LegibleDeserializedV0Advertisement`.
*/
-np_ffi_DeserializedV0Identity np_ffi_LegibleDeserializedV0Advertisement_into_identity(np_ffi_LegibleDeserializedV0Advertisement adv);
+np_ffi_DeserializedV0IdentityKind np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(np_ffi_LegibleDeserializedV0Advertisement adv);
/**
* Deallocates any internal data of a `LegibleDeserializedV0Advertisement`
@@ -761,11 +928,6 @@
np_ffi_DeallocateResult np_ffi_deallocate_legible_v0_advertisement(np_ffi_LegibleDeserializedV0Advertisement adv);
/**
- * Gets the tag of the `DeserializedV0Identity` tagged-union.
- */
-np_ffi_DeserializedV0IdentityKind np_ffi_DeserializedV0Identity_kind(np_ffi_DeserializedV0Identity identity);
-
-/**
* Attempts to get the data-element with the given index in the passed v0 adv payload
*/
np_ffi_GetV0DEResult np_ffi_V0Payload_get_de(np_ffi_V0Payload payload, uint8_t index);
diff --git a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h
index 3361c5d..ad3ec24 100644
--- a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h
+++ b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h
@@ -75,6 +75,20 @@
/// API call.
void np_ffi_global_config_set_num_shards(uint8_t num_shards);
+/// Sets the maximum number of active handles to credential slabs
+/// which may be active at any one time.
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on credential slabs in constrained-memory environments.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call utilizing credential slabs.
+void np_ffi_global_config_set_max_num_credential_slabs(uint32_t max_num_credential_slabs);
+
/// Sets the maximum number of active handles to credential books
/// which may be active at any one time.
/// Default value: Max value.
@@ -119,8 +133,9 @@
/// call which references or returns a deserialized V1 advertisement.
void np_ffi_global_config_set_max_num_deserialized_v1_advertisements(uint32_t max_num_deserialized_v1_advertisements);
-/// Allocates a new credential-book, returning a handle to the created object
-CreateCredentialBookResult np_ffi_create_credential_book();
+/// Allocates a new credential-book from the given slab, returning a handle
+/// to the created object. The slab will be deallocated by this call.
+CreateCredentialBookResult np_ffi_create_credential_book_from_slab(CredentialSlab slab);
/// Gets the tag of a `CreateCredentialBookResult` tagged enum.
CreateCredentialBookResultKind np_ffi_CreateCredentialBookResult_kind(CreateCredentialBookResult result);
@@ -129,9 +144,40 @@
/// case where the passed value is of a different enum variant.
CredentialBook np_ffi_CreateCredentialBookResult_into_SUCCESS(CreateCredentialBookResult result);
+/// Deallocates a credential-slab by its handle.
+DeallocateResult np_ffi_deallocate_credential_slab(CredentialSlab credential_slab);
+
/// Deallocates a credential-book by its handle
DeallocateResult np_ffi_deallocate_credential_book(CredentialBook credential_book);
+/// Allocates a new credential-slab, returning a handle to the created object
+CreateCredentialSlabResult np_ffi_create_credential_slab();
+
+/// Gets the tag of a `CreateCredentialSlabResult` tagged enum.
+CreateCredentialSlabResultKind np_ffi_CreateCredentialSlabResult_kind(CreateCredentialSlabResult result);
+
+/// Casts a `CreateCredentialSlabResult` to the `SUCCESS` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+CredentialSlab np_ffi_CreateCredentialSlabResult_into_SUCCESS(CreateCredentialSlabResult result);
+
+/// Adds the given V0 discovery credential with some associated
+/// match-data to this credential slab.
+///
+/// Safety: this is safe if the provided pointer points to a valid memory address
+/// which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
+/// so concurrent modification of the array from another thread would cause undefined behavior.
+AddCredentialToSlabResult np_ffi_CredentialSlab_add_v0_credential(CredentialSlab credential_slab,
+ V0MatchableCredential v0_cred);
+
+/// Adds the given V1 discovery credential with some associated
+/// match-data to this credential slab.
+///
+/// Safety: this is safe if the provided pointer points to a valid memory address
+/// which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
+/// so concurrent modification of the array from another thread would cause undefined behavior.
+AddCredentialToSlabResult np_ffi_CredentialSlab_add_v1_credential(CredentialSlab credential_slab,
+ V1MatchableCredential v1_cred);
+
/// Attempts to deserialize an advertisement with the given service-data
/// payload (presumed to be under the NP service UUID) using credentials
/// pulled from the given credential-book.
@@ -174,15 +220,12 @@
/// Gets just the data-element payload of a `LegibleDeserializedV0Advertisement`.
V0Payload np_ffi_LegibleDeserializedV0Advertisement_into_payload(LegibleDeserializedV0Advertisement adv);
-/// Gets just the identity information associated with a `LegibleDeserializedV0Advertisement`.
-DeserializedV0Identity np_ffi_LegibleDeserializedV0Advertisement_into_identity(LegibleDeserializedV0Advertisement adv);
+/// Gets just the identity kind associated with a `LegibleDeserializedV0Advertisement`.
+DeserializedV0IdentityKind np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(LegibleDeserializedV0Advertisement adv);
/// Deallocates any internal data of a `LegibleDeserializedV0Advertisement`
DeallocateResult np_ffi_deallocate_legible_v0_advertisement(LegibleDeserializedV0Advertisement adv);
-/// Gets the tag of the `DeserializedV0Identity` tagged-union.
-DeserializedV0IdentityKind np_ffi_DeserializedV0Identity_kind(DeserializedV0Identity identity);
-
/// Attempts to get the data-element with the given index in the passed v0 adv payload
GetV0DEResult np_ffi_V0Payload_get_de(V0Payload payload, uint8_t index);
diff --git a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h
index 4d66308..d39bb70 100644
--- a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h
+++ b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h
@@ -36,6 +36,14 @@
namespace np_ffi {
namespace internal {
+/// Result type for trying to add a credential to a credential-slab.
+enum class AddCredentialToSlabResult : uint8_t {
+ /// We succeeded in adding the credential to the slab.
+ Success = 0,
+ /// The handle to the slab was actually invalid.
+ InvalidHandle = 1,
+};
+
/// The possible boolean action types which can be present in an Actions data element
enum class BooleanActionType : uint8_t {
ActiveUnlock = 8,
@@ -49,11 +57,24 @@
/// Discriminant for `CreateCredentialBookResult`
enum class CreateCredentialBookResultKind : uint8_t {
- /// There was no space left to create a new credential book
- NoSpaceLeft = 0,
/// We created a new credential book behind the given handle.
/// The associated payload may be obtained via
/// `CreateCredentialBookResult#into_success()`.
+ Success = 0,
+ /// There was no space left to create a new credential book
+ NoSpaceLeft = 1,
+ /// The slab that we tried to create a credential-book from
+ /// actually was an invalid handle.
+ InvalidSlabHandle = 2,
+};
+
+/// Discriminant for `CreateCredentialSlabResult`
+enum class CreateCredentialSlabResultKind : uint8_t {
+ /// There was no space left to create a new credential slab
+ NoSpaceLeft = 0,
+ /// We created a new credential slab behind the given handle.
+ /// The associated payload may be obtained via
+ /// `CreateCredentialSlabResult#into_success()`.
Success = 1,
};
@@ -93,14 +114,8 @@
NoMatchingCredentials = 1,
};
-/// Represents deserialized information about the V0 identity utilized
-/// by a deserialized V0 advertisement
-enum class DeserializedV0Identity {
- Plaintext,
- Decrypted,
-};
-
-/// Discriminant for `DeserializedV0Identity`.
+/// Discriminant for deserialized information about the V0
+/// identity utilized by a deserialized V0 advertisement.
enum class DeserializedV0IdentityKind : uint8_t {
/// The deserialized identity was a plaintext identity.
Plaintext = 0,
@@ -193,8 +208,9 @@
/// Result type for `create_credential_book`
union CreateCredentialBookResult {
enum class Tag : uint8_t {
- NoSpaceLeft = 0,
- Success = 1,
+ Success = 0,
+ NoSpaceLeft = 1,
+ InvalidSlabHandle = 2,
};
struct Success_Body {
@@ -208,6 +224,67 @@
Success_Body success;
};
+///A `#[repr(C)]` handle to a value of type `super::CredentialSlabInternals`.
+struct CredentialSlab {
+ uint64_t handle_id;
+};
+
+/// Result type for `create_credential_slab`
+struct CreateCredentialSlabResult {
+ enum class Tag {
+ NoSpaceLeft,
+ Success,
+ };
+
+ struct Success_Body {
+ CredentialSlab _0;
+ };
+
+ Tag tag;
+ union {
+ Success_Body success;
+ };
+};
+
+/// Cryptographic information about a particular V0 discovery credential
+/// necessary to match and decrypt encrypted V0 advertisements.
+struct V0DiscoveryCredential {
+ uint8_t key_seed[32];
+ uint8_t legacy_metadata_key_hmac[32];
+};
+
+/// A representation of a MatchedCredential which is passable across the FFI boundary
+struct FfiMatchedCredential {
+ uint32_t cred_id;
+ const uint8_t *encrypted_metadata_bytes_buffer;
+ uintptr_t encrypted_metadata_bytes_len;
+};
+
+/// Representation of a V0 credential that contains additional data to provide back to caller once it
+/// is matched. The credential_id can be used by the caller to correlate it back to the full
+/// credentials details.
+struct V0MatchableCredential {
+ V0DiscoveryCredential discovery_cred;
+ FfiMatchedCredential matched_cred;
+};
+
+/// Cryptographic information about a particular V1 discovery credential
+/// necessary to match and decrypt encrypted V1 advertisement sections.
+struct V1DiscoveryCredential {
+ uint8_t key_seed[32];
+ uint8_t expected_unsigned_metadata_key_hmac[32];
+ uint8_t expected_signed_metadata_key_hmac[32];
+ uint8_t pub_key[32];
+};
+
+/// Representation of a V1 credential that contains additional data to provide back to caller once it
+/// is matched. The credential_id can be used by the caller to correlate it back to the full
+/// credentials details.
+struct V1MatchableCredential {
+ V1DiscoveryCredential discovery_cred;
+ FfiMatchedCredential matched_cred;
+};
+
///A `#[repr(C)]` handle to a value of type `super::V0PayloadInternals`.
struct V0Payload {
uint64_t handle_id;
@@ -217,7 +294,7 @@
struct LegibleDeserializedV0Advertisement {
uint8_t num_des;
V0Payload payload;
- DeserializedV0Identity identity;
+ DeserializedV0IdentityKind identity_kind;
};
/// Represents a deserialized V0 advertisement
@@ -409,6 +486,8 @@
/// This representation is stable, and so you may directly
/// reference this struct's fields if you wish.
struct GenericV1DataElement {
+ /// The offset of this generic data-element.
+ uint8_t offset;
/// The DE type code of this generic data-element.
V1DEType de_type;
/// The raw data-element byte payload, up to
diff --git a/nearby/presence/np_c_ffi/src/credentials.rs b/nearby/presence/np_c_ffi/src/credentials.rs
index 6b60545..70949a6 100644
--- a/nearby/presence/np_c_ffi/src/credentials.rs
+++ b/nearby/presence/np_c_ffi/src/credentials.rs
@@ -14,15 +14,20 @@
//! Credential-related data-types and functions
use crate::{unwrap, PanicReason};
+use core::slice;
use np_ffi_core::common::*;
use np_ffi_core::credentials::credential_book::CredentialBook;
+use np_ffi_core::credentials::credential_slab::CredentialSlab;
use np_ffi_core::credentials::*;
use np_ffi_core::utils::FfiEnum;
-/// Allocates a new credential-book, returning a handle to the created object
+/// Allocates a new credential-book from the given slab, returning a handle
+/// to the created object. The slab will be deallocated by this call.
#[no_mangle]
-pub extern "C" fn np_ffi_create_credential_book() -> CreateCredentialBookResult {
- create_credential_book()
+pub extern "C" fn np_ffi_create_credential_book_from_slab(
+ slab: CredentialSlab,
+) -> CreateCredentialBookResult {
+ create_credential_book_from_slab(slab)
}
/// Gets the tag of a `CreateCredentialBookResult` tagged enum.
@@ -42,6 +47,14 @@
unwrap(result.into_success(), PanicReason::EnumCastFailed)
}
+/// Deallocates a credential-slab by its handle.
+#[no_mangle]
+pub extern "C" fn np_ffi_deallocate_credential_slab(
+ credential_slab: CredentialSlab,
+) -> DeallocateResult {
+ deallocate_credential_slab(credential_slab)
+}
+
/// Deallocates a credential-book by its handle
#[no_mangle]
pub extern "C" fn np_ffi_deallocate_credential_book(
@@ -49,3 +62,98 @@
) -> DeallocateResult {
deallocate_credential_book(credential_book)
}
+
+/// Allocates a new credential-slab, returning a handle to the created object
+#[no_mangle]
+pub extern "C" fn np_ffi_create_credential_slab() -> CreateCredentialSlabResult {
+ create_credential_slab()
+}
+
+/// Gets the tag of a `CreateCredentialSlabResult` tagged enum.
+#[no_mangle]
+pub extern "C" fn np_ffi_CreateCredentialSlabResult_kind(
+ result: CreateCredentialSlabResult,
+) -> CreateCredentialSlabResultKind {
+ result.kind()
+}
+
+/// Casts a `CreateCredentialSlabResult` to the `SUCCESS` variant, panicking in the
+/// case where the passed value is of a different enum variant.
+#[no_mangle]
+pub extern "C" fn np_ffi_CreateCredentialSlabResult_into_SUCCESS(
+ result: CreateCredentialSlabResult,
+) -> CredentialSlab {
+ unwrap(result.into_success(), PanicReason::EnumCastFailed)
+}
+
+/// Representation of a V0 credential that contains additional data to provide back to caller once it
+/// is matched. The credential_id can be used by the caller to correlate it back to the full
+/// credentials details.
+#[repr(C)]
+pub struct V0MatchableCredential {
+ discovery_cred: V0DiscoveryCredential,
+ matched_cred: FfiMatchedCredential,
+}
+
+/// Representation of a V1 credential that contains additional data to provide back to caller once it
+/// is matched. The credential_id can be used by the caller to correlate it back to the full
+/// credentials details.
+#[repr(C)]
+pub struct V1MatchableCredential {
+ discovery_cred: V1DiscoveryCredential,
+ matched_cred: FfiMatchedCredential,
+}
+
+/// A representation of a MatchedCredential which is passable across the FFI boundary
+#[repr(C)]
+pub struct FfiMatchedCredential {
+ cred_id: u32,
+ encrypted_metadata_bytes_buffer: *const u8,
+ encrypted_metadata_bytes_len: usize,
+}
+
+/// Adds the given V0 discovery credential with some associated
+/// match-data to this credential slab.
+///
+/// Safety: this is safe if the provided pointer points to a valid memory address
+/// which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
+/// so concurrent modification of the array from another thread would cause undefined behavior.
+#[no_mangle]
+pub extern "C" fn np_ffi_CredentialSlab_add_v0_credential(
+ credential_slab: CredentialSlab,
+ v0_cred: V0MatchableCredential,
+) -> AddCredentialToSlabResult {
+ #[allow(unsafe_code)]
+ let metadata_slice = unsafe {
+ slice::from_raw_parts(
+ v0_cred.matched_cred.encrypted_metadata_bytes_buffer,
+ v0_cred.matched_cred.encrypted_metadata_bytes_len,
+ )
+ };
+
+ let matched_credential = MatchedCredential::new(v0_cred.matched_cred.cred_id, metadata_slice);
+ credential_slab.add_v0(v0_cred.discovery_cred, matched_credential)
+}
+
+/// Adds the given V1 discovery credential with some associated
+/// match-data to this credential slab.
+///
+/// Safety: this is safe if the provided pointer points to a valid memory address
+/// which contains the correct len amount of bytes. The copy from the memory address isn't atomic,
+/// so concurrent modification of the array from another thread would cause undefined behavior.
+#[no_mangle]
+pub extern "C" fn np_ffi_CredentialSlab_add_v1_credential(
+ credential_slab: CredentialSlab,
+ v1_cred: V1MatchableCredential,
+) -> AddCredentialToSlabResult {
+ #[allow(unsafe_code)]
+ let metadata_slice = unsafe {
+ slice::from_raw_parts(
+ v1_cred.matched_cred.encrypted_metadata_bytes_buffer,
+ v1_cred.matched_cred.encrypted_metadata_bytes_len,
+ )
+ };
+
+ let matched_credential = MatchedCredential::new(v1_cred.matched_cred.cred_id, metadata_slice);
+ credential_slab.add_v1(v1_cred.discovery_cred, matched_credential)
+}
diff --git a/nearby/presence/np_c_ffi/src/deserialize/v0.rs b/nearby/presence/np_c_ffi/src/deserialize/v0.rs
index 24c4c2a..28bec8a 100644
--- a/nearby/presence/np_c_ffi/src/deserialize/v0.rs
+++ b/nearby/presence/np_c_ffi/src/deserialize/v0.rs
@@ -52,12 +52,12 @@
adv.payload()
}
-/// Gets just the identity information associated with a `LegibleDeserializedV0Advertisement`.
+/// Gets just the identity kind associated with a `LegibleDeserializedV0Advertisement`.
#[no_mangle]
-pub extern "C" fn np_ffi_LegibleDeserializedV0Advertisement_into_identity(
+pub extern "C" fn np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(
adv: LegibleDeserializedV0Advertisement,
-) -> DeserializedV0Identity {
- adv.identity()
+) -> DeserializedV0IdentityKind {
+ adv.identity_kind()
}
/// Deallocates any internal data of a `LegibleDeserializedV0Advertisement`
@@ -68,14 +68,6 @@
adv.deallocate()
}
-/// Gets the tag of the `DeserializedV0Identity` tagged-union.
-#[no_mangle]
-pub extern "C" fn np_ffi_DeserializedV0Identity_kind(
- identity: DeserializedV0Identity,
-) -> DeserializedV0IdentityKind {
- identity.kind()
-}
-
/// Attempts to get the data-element with the given index in the passed v0 adv payload
#[no_mangle]
pub extern "C" fn np_ffi_V0Payload_get_de(payload: V0Payload, index: u8) -> GetV0DEResult {
diff --git a/nearby/presence/np_c_ffi/src/lib.rs b/nearby/presence/np_c_ffi/src/lib.rs
index 0dd6d33..84e9859 100644
--- a/nearby/presence/np_c_ffi/src/lib.rs
+++ b/nearby/presence/np_c_ffi/src/lib.rs
@@ -147,6 +147,23 @@
np_ffi_core::common::global_config_set_num_shards(num_shards)
}
+/// Sets the maximum number of active handles to credential slabs
+/// which may be active at any one time.
+/// Default value: Max value.
+/// Max value: `u32::MAX - 1`.
+///
+/// Useful for bounding the maximum memory used by the client application
+/// on credential slabs in constrained-memory environments.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call utilizing credential slabs.
+#[no_mangle]
+pub extern "C" fn np_ffi_global_config_set_max_num_credential_slabs(max_num_credential_slabs: u32) {
+ np_ffi_core::common::global_config_set_max_num_credential_slabs(max_num_credential_slabs)
+}
+
/// Sets the maximum number of active handles to credential books
/// which may be active at any one time.
/// Default value: Max value.
diff --git a/nearby/presence/np_cpp_ffi/benchmarks/np_ffi_bench.cc b/nearby/presence/np_cpp_ffi/benchmarks/np_ffi_bench.cc
index 72a3f91..164bab3 100644
--- a/nearby/presence/np_cpp_ffi/benchmarks/np_ffi_bench.cc
+++ b/nearby/presence/np_cpp_ffi/benchmarks/np_ffi_bench.cc
@@ -40,7 +40,9 @@
BENCHMARK_DEFINE_F(NpCppBenchmark, V0PlaintextAdvertisement)
(benchmark::State &state) {
- auto cred_book = nearby_protocol::CredentialBook::TryCreate();
+ auto cred_slab = nearby_protocol::CredentialSlab::TryCreate();
+ assert(cred_slab.ok());
+ auto cred_book = nearby_protocol::CredentialBook::TryCreateFromSlab(cred_slab.value());
assert(cred_book.ok());
auto num_ciphers = state.range(0);
@@ -68,7 +70,14 @@
BENCHMARK_DEFINE_F(NpCBenchmark, V0PlaintextAdvertisement)
(benchmark::State &state) {
auto num_ciphers = state.range(0);
- auto book_result = np_ffi::internal::np_ffi_create_credential_book();
+ auto slab_result = np_ffi::internal::np_ffi_create_credential_slab();
+ assert(
+ np_ffi::internal::np_ffi_CreateCredentialSlabResult_kind(slab_result) ==
+ np_ffi::internal::CreateCredentialSlabResultKind::Success);
+ auto slab = np_ffi::internal::np_ffi_CreateCredentialSlabResult_into_SUCCESS(
+ slab_result);
+
+ auto book_result = np_ffi::internal::np_ffi_create_credential_book_from_slab(slab);
assert(
np_ffi::internal::np_ffi_CreateCredentialBookResult_kind(book_result) ==
np_ffi::internal::CreateCredentialBookResultKind::Success);
@@ -99,4 +108,4 @@
->Range(1, 1000)
->Unit(benchmark::kMicrosecond);
-BENCHMARK_MAIN();
\ No newline at end of file
+BENCHMARK_MAIN();
diff --git a/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_deserialize.cc b/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_deserialize.cc
index 84d7247..3c409e7 100644
--- a/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_deserialize.cc
+++ b/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_deserialize.cc
@@ -34,7 +34,13 @@
nearby_protocol::RawAdvertisementPayload payload(
(nearby_protocol::ByteBuffer<255>(raw_bytes)));
- auto credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ if (!credential_slab.ok()) {
+ printf("Error: create Credential slab failed\n");
+ __builtin_trap();
+ }
+
+ auto credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(credential_slab.value());
if (!credential_book.ok()) {
printf("Error: create Credential book failed\n");
__builtin_trap();
@@ -45,4 +51,4 @@
payload, credential_book.value());
return 0;
-}
\ No newline at end of file
+}
diff --git a/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_valid_header.cc b/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_valid_header.cc
index c08b6cd..2475b5e 100644
--- a/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_valid_header.cc
+++ b/nearby/presence/np_cpp_ffi/fuzz/fuzzer_np_cpp_valid_header.cc
@@ -32,7 +32,13 @@
nearby_protocol::RawAdvertisementPayload payload(
(nearby_protocol::ByteBuffer<255>(raw_bytes)));
- auto credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ if (!credential_slab.ok()) {
+ printf("Error: create Credential slab failed\n");
+ __builtin_trap();
+ }
+
+ auto credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(credential_slab.value());
if (!credential_book.ok()) {
printf("Error: create Credential book failed\n");
__builtin_trap();
@@ -51,4 +57,4 @@
payload, credential_book.value());
return 0;
-}
\ No newline at end of file
+}
diff --git a/nearby/presence/np_cpp_ffi/include/nearby_protocol.h b/nearby/presence/np_cpp_ffi/include/nearby_protocol.h
index e7e46e7..1e16eef 100644
--- a/nearby/presence/np_cpp_ffi/include/nearby_protocol.h
+++ b/nearby/presence/np_cpp_ffi/include/nearby_protocol.h
@@ -51,6 +51,7 @@
// Re-exporting cbindgen generated types which are used in the public API
using np_ffi::internal::BooleanActionType;
+using np_ffi::internal::CreateCredentialSlabResultKind;
using np_ffi::internal::CreateCredentialBookResultKind;
using np_ffi::internal::DeserializeAdvertisementResultKind;
using np_ffi::internal::DeserializedV0AdvertisementKind;
@@ -71,7 +72,6 @@
// V0 Classes
class DeserializedV0Advertisement;
-class DeserializedV0Identity;
class LegibleDeserializedV0Advertisement;
class V0DataElement;
class V0Payload;
@@ -109,6 +109,12 @@
// np_ffi_global_config_set_num_shards in np_cpp_ffi_functions.h for more info
static void SetNumShards(uint8_t num_shards);
+ // Sets the maximum number of active handles to credential slabs which may be
+ // active at any one time. See
+ // np_ffi_global_config_set_max_num_credential_slabs in np_cpp_ffi_functions.h
+ // for more info
+ static void SetMaxNumCredentialSlabs(uint32_t max_num_credential_slabs);
+
// Sets the maximum number of active handles to credential books which may be
// active at any one time. See
// np_ffi_global_config_set_max_num_credential_books in np_cpp_ffi_functions.h
@@ -128,6 +134,37 @@
uint32_t max_num_deserialized_v1_advertisements);
};
+// Holds the credentials used in the construction of a credential book
+// using CredentialBook::TryCreateFromSlab()
+class CredentialSlab {
+public:
+ // Don't allow copy constructor or copy assignment, since that would result in
+ // the underlying handle being freed multiple times
+ CredentialSlab(const CredentialSlab &other) = delete;
+ CredentialSlab &operator=(const CredentialSlab &other) = delete;
+
+ // Move constructor and move assignment are needed in order to wrap this class
+ // in absl::StatusOr
+ CredentialSlab(CredentialSlab &&other) noexcept;
+ CredentialSlab &operator=(CredentialSlab &&other) noexcept;
+
+ // The destructor for a CredentialSlab, this will be called when a
+ // CredentialSlab instance goes out of scope and will free the underlying
+ // resources
+ ~CredentialSlab();
+
+ // Creates a new instance of a CredentialSlab, returns the CredentialSlab on
+ // success or a Status code on failure
+ [[nodiscard]] static absl::StatusOr<CredentialSlab> TryCreate();
+private:
+ friend class CredentialBook;
+ explicit CredentialSlab(np_ffi::internal::CredentialSlab credential_slab)
+ : credential_slab_(credential_slab), moved_(false) {}
+
+ np_ffi::internal::CredentialSlab credential_slab_;
+ bool moved_;
+};
+
// Holds the credentials used when decrypting data of an advertisement.
// This needs to be passed to Deserializer::DeserializeAdvertisement() when
// attempting to deserialize a payload
@@ -148,9 +185,11 @@
// resources
~CredentialBook();
- // Creates a new instance of a CredentialBook, returns the CredentialBook on
- // success or a Status code on failure
- [[nodiscard]] static absl::StatusOr<CredentialBook> TryCreate();
+ // Creates a new instance of a CredentialBook from a CredentialSlab,
+ // returning the CredentialBook on success or a Status code on failure.
+ // The passed credential-slab will be deallocated if this operation
+ // is successful.
+ [[nodiscard]] static absl::StatusOr<CredentialBook> TryCreateFromSlab(CredentialSlab &slab);
private:
friend class Deserializer;
@@ -339,8 +378,9 @@
// and will free the underlying parent handle.
~LegibleDeserializedV0Advertisement();
- // Returns just the identity information associated with the advertisement
- [[nodiscard]] DeserializedV0Identity GetIdentity();
+ // Returns just the kind of identity (public/encrypted)
+ // associated with the advertisement
+ [[nodiscard]] DeserializedV0IdentityKind GetIdentityKind();
// Returns the number of data elements in the advertisement
[[nodiscard]] uint8_t GetNumberOfDataElements();
// Returns just the data-element payload of the advertisement
@@ -358,20 +398,6 @@
bool moved_;
};
-// A V0 identity of an advertisement
-class DeserializedV0Identity {
-public:
- // Returns the DeserializedV0IdentityKind of the advertisement
- [[nodiscard]] DeserializedV0IdentityKind GetKind();
-
-private:
- friend class LegibleDeserializedV0Advertisement;
- explicit DeserializedV0Identity(
- np_ffi::internal::DeserializedV0Identity v0_identity)
- : v0_identity_(v0_identity) {}
- np_ffi::internal::DeserializedV0Identity v0_identity_;
-};
-
// A data element payload of a Deserialized V0 Advertisement.
class V0Payload {
public:
diff --git a/nearby/presence/np_cpp_ffi/nearby_protocol.cc b/nearby/presence/np_cpp_ffi/nearby_protocol.cc
index 3ee5c63..106eb77 100644
--- a/nearby/presence/np_cpp_ffi/nearby_protocol.cc
+++ b/nearby/presence/np_cpp_ffi/nearby_protocol.cc
@@ -67,6 +67,11 @@
np_ffi::internal::np_ffi_global_config_set_num_shards(num_shards);
}
+void GlobalConfig::SetMaxNumCredentialSlabs(uint32_t max_num_credential_slabs) {
+ np_ffi::internal::np_ffi_global_config_set_max_num_credential_slabs(
+ max_num_credential_slabs);
+}
+
void GlobalConfig::SetMaxNumCredentialBooks(uint32_t max_num_credential_books) {
np_ffi::internal::np_ffi_global_config_set_max_num_credential_books(
max_num_credential_books);
@@ -86,21 +91,73 @@
max_num_deserialized_v1_advertisements);
}
-absl::StatusOr<CredentialBook> CredentialBook::TryCreate() {
- auto result = np_ffi::internal::np_ffi_create_credential_book();
- auto kind = np_ffi::internal::np_ffi_CreateCredentialBookResult_kind(result);
+absl::StatusOr<CredentialSlab> CredentialSlab::TryCreate() {
+ auto result = np_ffi::internal::np_ffi_create_credential_slab();
+ auto kind = np_ffi::internal::np_ffi_CreateCredentialSlabResult_kind(result);
switch (kind) {
- case CreateCredentialBookResultKind::Success: {
- auto book = CredentialBook(
- np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS(
+ case CreateCredentialSlabResultKind::Success: {
+ auto slab = CredentialSlab(
+ np_ffi::internal::np_ffi_CreateCredentialSlabResult_into_SUCCESS(
result));
- return book;
+ return slab;
+ }
+ case CreateCredentialSlabResultKind::NoSpaceLeft: {
+ return absl::ResourceExhaustedError(
+ "No space left to create credential slab");
+ }
+ }
+}
+
+CredentialSlab::~CredentialSlab() {
+ if (!this->moved_) {
+ auto result =
+ np_ffi::internal::np_ffi_deallocate_credential_slab(credential_slab_);
+ assert_panic(result == np_ffi::internal::DeallocateResult::Success);
+ }
+}
+
+CredentialSlab::CredentialSlab(CredentialSlab &&other) noexcept
+ : credential_slab_(other.credential_slab_), moved_(other.moved_) {
+ other.credential_slab_ = {};
+ other.moved_ = true;
+}
+
+CredentialSlab &CredentialSlab::operator=(CredentialSlab &&other) noexcept {
+ if (this != &other) {
+ if (!this->moved_) {
+ auto result = np_ffi::internal::np_ffi_deallocate_credential_slab(
+ this->credential_slab_);
+ assert_panic(result == np_ffi::internal::DeallocateResult::Success);
+ }
+
+ this->credential_slab_ = other.credential_slab_;
+ this->moved_ = other.moved_;
+
+ other.credential_slab_ = {};
+ other.moved_ = true;
+ }
+ return *this;
+}
+
+absl::StatusOr<CredentialBook> CredentialBook::TryCreateFromSlab(CredentialSlab &slab) {
+ assert_panic(!slab.moved_);
+ auto result = np_ffi::internal::np_ffi_create_credential_book_from_slab(slab.credential_slab_);
+ auto kind = np_ffi::internal::np_ffi_CreateCredentialBookResult_kind(result);
+ switch (kind) {
+ case CreateCredentialBookResultKind::Success: {
+ auto book = np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS(result);
+ slab.moved_ = true;
+ return CredentialBook(book);
}
case CreateCredentialBookResultKind::NoSpaceLeft: {
return absl::ResourceExhaustedError(
"No space left to create credential book");
}
+ case CreateCredentialBookResultKind::InvalidSlabHandle: {
+ return absl::NotFoundError(
+ "The slab referenced by the given handle was not found.");
+ }
}
}
@@ -286,12 +343,12 @@
}
}
-DeserializedV0Identity LegibleDeserializedV0Advertisement::GetIdentity() {
+DeserializedV0IdentityKind LegibleDeserializedV0Advertisement::GetIdentityKind() {
assert_panic(!this->moved_);
auto result =
- np_ffi::internal::np_ffi_LegibleDeserializedV0Advertisement_into_identity(
+ np_ffi::internal::np_ffi_LegibleDeserializedV0Advertisement_get_identity_kind(
legible_v0_advertisement_);
- return DeserializedV0Identity(result);
+ return result;
}
uint8_t LegibleDeserializedV0Advertisement::GetNumberOfDataElements() {
@@ -309,10 +366,6 @@
return V0Payload(result);
}
-np_ffi::internal::DeserializedV0IdentityKind DeserializedV0Identity::GetKind() {
- return np_ffi::internal::np_ffi_DeserializedV0Identity_kind(v0_identity_);
-}
-
V0Payload::V0Payload(V0Payload &&other) noexcept
: v0_payload_(other.v0_payload_), moved_(other.moved_) {
other.v0_payload_ = {};
diff --git a/nearby/presence/np_cpp_ffi/sample/main.cc b/nearby/presence/np_cpp_ffi/sample/main.cc
index a18b996..a02a523 100644
--- a/nearby/presence/np_cpp_ffi/sample/main.cc
+++ b/nearby/presence/np_cpp_ffi/sample/main.cc
@@ -25,7 +25,7 @@
void HandleV0Adv(nearby_protocol::DeserializedV0Advertisement);
void HandleLegibleV0Adv(nearby_protocol::LegibleDeserializedV0Advertisement);
-void HandleV0Identity(nearby_protocol::DeserializedV0Identity);
+void HandleV0IdentityKind(nearby_protocol::DeserializedV0IdentityKind);
void HandleDataElement(nearby_protocol::V0DataElement);
void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement);
@@ -46,8 +46,15 @@
std::cout << "\n========= Example V0 Adv ==========\n";
std::cout << "Hex bytes: 00031503260046\n\n";
- // Create an empty credential book and verify that is is successful
- auto cred_book_result = nearby_protocol::CredentialBook::TryCreate();
+ // Create an empty credential slab and verify that it is successful
+ auto cred_slab_result = nearby_protocol::CredentialSlab::TryCreate();
+ if (!cred_slab_result.ok()) {
+ std::cout << cred_slab_result.status().ToString();
+ return -1;
+ }
+
+ // Create an empty credential book from the empty slab, and verify success.
+ auto cred_book_result = nearby_protocol::CredentialBook::TryCreateFromSlab(cred_slab_result.value());
if (!cred_book_result.ok()) {
std::cout << cred_book_result.status().ToString();
return -1;
@@ -171,7 +178,7 @@
void HandleLegibleV0Adv(
nearby_protocol::LegibleDeserializedV0Advertisement legible_adv) {
- HandleV0Identity(legible_adv.GetIdentity());
+ HandleV0IdentityKind(legible_adv.GetIdentityKind());
auto num_des = legible_adv.GetNumberOfDataElements();
std::cout << "\t\tAdv contains " << unsigned(num_des) << " data elements \n";
@@ -187,8 +194,8 @@
}
}
-void HandleV0Identity(nearby_protocol::DeserializedV0Identity identity) {
- switch (identity.GetKind()) {
+void HandleV0IdentityKind(nearby_protocol::DeserializedV0IdentityKind identity) {
+ switch (identity) {
case np_ffi::internal::DeserializedV0IdentityKind::Plaintext: {
std::cout << "\t\tIdentity is Plaintext\n";
break;
diff --git a/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt b/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt
index 7ca9eb0..b5ff838 100644
--- a/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt
+++ b/nearby/presence/np_cpp_ffi/tests/CMakeLists.txt
@@ -17,6 +17,7 @@
deserialize_result_tests.cc
deserialize_v0_tests.cc
deserialize_v1_tests.cc
+ credential_slab_tests.cc
credential_book_tests.cc
byte_buffer_tests.cc
np_cpp_test.h
diff --git a/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc b/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc
index 4bca8ec..15f262e 100644
--- a/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc
@@ -70,9 +70,10 @@
nearby_protocol::RawAdvertisementPayload adv(buffer.value());
- auto credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto credential_slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(credential_slab).value();
auto str = nearby_protocol::Deserializer::DeserializeAdvertisement(
- adv, credential_book.value())
+ adv, credential_book)
.IntoV1()
.TryGetSection(0)
.value()
diff --git a/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc b/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc
index 3a32904..dcaf421 100644
--- a/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc
@@ -19,19 +19,27 @@
#include "gtest/gtest.h"
TEST_F(NpCppTest, TestSetMaxCredBooks) {
- auto book1_result = nearby_protocol::CredentialBook::TryCreate();
+ auto slab1_result = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(slab1_result.ok());
+ auto book1_result = nearby_protocol::CredentialBook::TryCreateFromSlab(slab1_result.value());
ASSERT_TRUE(book1_result.ok());
- auto book2_result = nearby_protocol::CredentialBook::TryCreate();
+ auto slab2_result = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(slab2_result.ok());
+ auto book2_result = nearby_protocol::CredentialBook::TryCreateFromSlab(slab2_result.value());
ASSERT_TRUE(book2_result.ok());
- auto book3_result = nearby_protocol::CredentialBook::TryCreate();
+ auto slab3_result = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(slab3_result.ok());
+ auto book3_result = nearby_protocol::CredentialBook::TryCreateFromSlab(slab3_result.value());
+
ASSERT_FALSE(book3_result.ok());
ASSERT_TRUE(absl::IsResourceExhausted(book3_result.status()));
}
TEST_F(NpCppTest, TestMoveConstructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvSimple,
book);
@@ -62,7 +70,8 @@
}
TEST_F(NpCppTest, TestMoveAssignment) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvSimple,
book);
@@ -70,7 +79,8 @@
np_ffi::internal::DeserializeAdvertisementResultKind::V0);
// create a second empty credential book
- auto other_book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto other_slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto other_book = nearby_protocol::CredentialBook::TryCreateFromSlab(other_slab).value();
other_book = std::move(book);
// new credential book should still be successful
@@ -92,4 +102,4 @@
nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, another_moved_book),
"");
-}
\ No newline at end of file
+}
diff --git a/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc b/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc
new file mode 100644
index 0000000..f715361
--- /dev/null
+++ b/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc
@@ -0,0 +1,56 @@
+// 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.
+
+#include "nearby_protocol.h"
+#include "shared_test_util.h"
+#include "np_cpp_test.h"
+
+#include "gtest/gtest.h"
+
+TEST_F(NpCppTest, TestSetMaxCredSlabs) {
+ auto slab1_result = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(slab1_result.ok());
+
+ auto slab2_result = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(slab2_result.ok());
+
+ auto slab3_result = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(slab3_result.ok());
+
+ auto slab4_result = nearby_protocol::CredentialSlab::TryCreate();
+
+ ASSERT_FALSE(slab4_result.ok());
+ ASSERT_TRUE(absl::IsResourceExhausted(slab4_result.status()));
+}
+
+TEST_F(NpCppTest, TestSlabMoveConstructor) {
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ // It should be possible to move the slab into a new object
+ // and use the moved version to successfully construct a
+ // credential-book.
+ nearby_protocol::CredentialSlab next_slab(std::move(slab));
+
+ auto maybe_book = nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab);
+ ASSERT_TRUE(maybe_book.ok());
+
+ // Now, both slabs should be moved-out-of, since `TryCreateFromSlab` takes
+ // ownership. Verify that this is the case, and attempts to re-use the slabs
+ // result in an assert failure.
+ ASSERT_DEATH([[maybe_unused]] auto failure =
+ nearby_protocol::CredentialBook::TryCreateFromSlab(slab), //NOLINT(bugprone-use-after-move)
+ "");
+ ASSERT_DEATH([[maybe_unused]] auto failure =
+ nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab),
+ "");
+}
diff --git a/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc b/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc
index 737fd18..0469933 100644
--- a/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc
@@ -20,7 +20,8 @@
#include "gtest/gtest.h"
TEST_F(NpCppTest, TestResultMoveConstructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -57,8 +58,12 @@
nearby_protocol::RawAdvertisementPayload adv(buffer.value());
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
+
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
adv, maybe_credential_book.value());
@@ -70,8 +75,8 @@
ASSERT_EQ(v0_adv.GetKind(),
nearby_protocol::DeserializedV0AdvertisementKind::Legible);
auto legible_adv = v0_adv.IntoLegible();
- auto identity = legible_adv.GetIdentity();
- ASSERT_EQ(identity.GetKind(),
+ auto identity = legible_adv.GetIdentityKind();
+ ASSERT_EQ(identity,
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
auto num_des = legible_adv.GetNumberOfDataElements();
@@ -88,7 +93,8 @@
}
TEST_F(NpCppTest, TestResultMoveAssignment) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -124,8 +130,13 @@
// An invalid header result should result in error
nearby_protocol::RawAdvertisementPayload InvalidHeaderPayload(
nearby_protocol::ByteBuffer<255>({1, {0xFF}}));
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
+
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
InvalidHeaderPayload, maybe_credential_book.value());
@@ -140,7 +151,12 @@
}
TEST_F(NpCppTest, TestInvalidV0Cast) {
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
+ ASSERT_TRUE(maybe_credential_book.ok());
+
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
V1AdvSimple, maybe_credential_book.value());
@@ -153,8 +169,13 @@
TEST_F(NpCppTest, TestInvalidV1Cast) {
// Create an empty credential book and verify that is is successful
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
+
+
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, maybe_credential_book.value());
@@ -166,12 +187,15 @@
}
TEST_F(NpCppTest, V0UseResultTwice) {
- auto book_result = nearby_protocol::CredentialBook::TryCreate();
- ASSERT_TRUE(book_result.ok());
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
+ ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
- V0AdvSimple, book_result.value());
+ V0AdvSimple, maybe_credential_book.value());
ASSERT_EQ(deserialize_result.GetKind(),
np_ffi::internal::DeserializeAdvertisementResultKind::V0);
@@ -184,12 +208,15 @@
}
TEST_F(NpCppTest, V1UseResultTwice) {
- auto book_result = nearby_protocol::CredentialBook::TryCreate();
- ASSERT_TRUE(book_result.ok());
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
+ ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
- V1AdvSimple, book_result.value());
+ V1AdvSimple, maybe_credential_book.value());
ASSERT_EQ(deserialize_result.GetKind(),
np_ffi::internal::DeserializeAdvertisementResultKind::V1);
@@ -202,12 +229,15 @@
}
TEST_F(NpCppTest, IntoV0AfterOutOfScope) {
- auto book_result = nearby_protocol::CredentialBook::TryCreate();
- ASSERT_TRUE(book_result.ok());
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
+ ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
- V0AdvSimple, book_result.value());
+ V0AdvSimple, maybe_credential_book.value());
ASSERT_EQ(deserialize_result.GetKind(),
np_ffi::internal::DeserializeAdvertisementResultKind::V0);
@@ -221,12 +251,15 @@
}
TEST_F(NpCppTest, IntoV1AfterOutOfScope) {
- auto book_result = nearby_protocol::CredentialBook::TryCreate();
- ASSERT_TRUE(book_result.ok());
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
+ ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
- V1AdvSimple, book_result.value());
+ V1AdvSimple, maybe_credential_book.value());
ASSERT_EQ(deserialize_result.GetKind(),
np_ffi::internal::DeserializeAdvertisementResultKind::V1);
@@ -240,12 +273,15 @@
}
TEST_F(NpCppTest, V0ResultKindAfterOutOfScope) {
- auto book_result = nearby_protocol::CredentialBook::TryCreate();
- ASSERT_TRUE(book_result.ok());
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
+ ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
- V0AdvSimple, book_result.value());
+ V0AdvSimple, maybe_credential_book.value());
ASSERT_EQ(deserialize_result.GetKind(),
np_ffi::internal::DeserializeAdvertisementResultKind::V0);
@@ -259,12 +295,15 @@
}
TEST_F(NpCppTest, V1ResultKindAfterOutOfScope) {
- auto book_result = nearby_protocol::CredentialBook::TryCreate();
- ASSERT_TRUE(book_result.ok());
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
+ ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
- V1AdvSimple, book_result.value());
+ V1AdvSimple, maybe_credential_book.value());
ASSERT_EQ(deserialize_result.GetKind(),
np_ffi::internal::DeserializeAdvertisementResultKind::V1);
@@ -275,4 +314,4 @@
// in a crash.
ASSERT_DEATH(
{ [[maybe_unused]] auto failure = deserialize_result.GetKind(); }, "");
-}
\ No newline at end of file
+}
diff --git a/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc b/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc
index e2a10a0..54b17ab 100644
--- a/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/deserialize_v0_tests.cc
@@ -19,7 +19,8 @@
#include "gtest/gtest.h"
TEST_F(NpCppTest, InvalidCast) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvSimple, book);
ASSERT_EQ(deserialize_result.GetKind(),
@@ -40,7 +41,8 @@
0x15, 0x03} // Length 1 Tx Power DE with value 3
}));
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab);
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -53,8 +55,8 @@
ASSERT_EQ(v0_adv.GetKind(),
nearby_protocol::DeserializedV0AdvertisementKind::Legible);
auto legible_adv = v0_adv.IntoLegible();
- auto identity = legible_adv.GetIdentity();
- ASSERT_EQ(identity.GetKind(),
+ auto identity = legible_adv.GetIdentityKind();
+ ASSERT_EQ(identity,
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
auto num_des = legible_adv.GetNumberOfDataElements();
@@ -79,7 +81,9 @@
0x16, 0x00} // Length 1 Actions DE
}));
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -92,8 +96,8 @@
ASSERT_EQ(v0_adv.GetKind(),
nearby_protocol::DeserializedV0AdvertisementKind::Legible);
auto legible_adv = v0_adv.IntoLegible();
- auto identity = legible_adv.GetIdentity();
- ASSERT_EQ(identity.GetKind(),
+ auto identity = legible_adv.GetIdentityKind();
+ ASSERT_EQ(identity,
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
auto num_des = legible_adv.GetNumberOfDataElements();
@@ -118,7 +122,9 @@
0x26, 0xD0, 0x46} // Length 2 Actions DE
}));
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -131,8 +137,8 @@
ASSERT_EQ(v0_adv.GetKind(),
nearby_protocol::DeserializedV0AdvertisementKind::Legible);
auto legible_adv = v0_adv.IntoLegible();
- auto identity = legible_adv.GetIdentity();
- ASSERT_EQ(identity.GetKind(),
+ auto identity = legible_adv.GetIdentityKind();
+ ASSERT_EQ(identity,
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
auto num_des = legible_adv.GetNumberOfDataElements();
@@ -174,7 +180,9 @@
0x26, 0x00, 0x46, // Length 2 Actions
}}));
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -187,8 +195,8 @@
ASSERT_EQ(v0_adv.GetKind(),
nearby_protocol::DeserializedV0AdvertisementKind::Legible);
auto legible_adv = v0_adv.IntoLegible();
- auto identity = legible_adv.GetIdentity();
- ASSERT_EQ(identity.GetKind(),
+ auto identity = legible_adv.GetIdentityKind();
+ ASSERT_EQ(identity,
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
auto num_des = legible_adv.GetNumberOfDataElements();
@@ -214,7 +222,9 @@
}
TEST_F(NpCppTest, V0EmptyPayload) {
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -225,7 +235,8 @@
}
TEST_F(NpCppTest, TestV0AdvMoveConstructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -252,7 +263,8 @@
}
TEST_F(NpCppTest, TestV0AdvMoveAssignment) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -292,7 +304,9 @@
}
TEST_F(NpCppTest, V0AdvDestructor) {
- auto book_result = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto book_result = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(book_result.ok());
{
auto deserialize_result = CreateAdv(book_result.value());
@@ -326,7 +340,9 @@
}
TEST_F(NpCppTest, V0AdvUseAfterMove) {
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -346,7 +362,8 @@
}
TEST_F(NpCppTest, TestLegibleAdvMoveConstructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -356,13 +373,13 @@
// Now move the adv into a new value, and make sure its still valid
nearby_protocol::LegibleDeserializedV0Advertisement moved(std::move(legible));
ASSERT_EQ(moved.GetNumberOfDataElements(), 1);
- ASSERT_EQ(moved.GetIdentity().GetKind(),
+ ASSERT_EQ(moved.GetIdentityKind(),
np_ffi::internal::DeserializedV0IdentityKind::Plaintext);
// trying to use the moved object should result in a use after free which
// triggers an abort
ASSERT_DEATH([[maybe_unused]] auto failure =
- legible.GetIdentity(), // NOLINT(bugprone-use-after-move
+ legible.GetIdentityKind(), // NOLINT(bugprone-use-after-move
"");
ASSERT_DEATH(
[[maybe_unused]] auto failure = legible.GetNumberOfDataElements(), "");
@@ -372,7 +389,7 @@
// abort
nearby_protocol::LegibleDeserializedV0Advertisement moved_again(
std::move(legible));
- ASSERT_DEATH([[maybe_unused]] auto failure = moved_again.GetIdentity(), "");
+ ASSERT_DEATH([[maybe_unused]] auto failure = moved_again.GetIdentityKind(), "");
ASSERT_DEATH([[maybe_unused]] auto failure =
moved_again.GetNumberOfDataElements(),
"");
@@ -380,7 +397,8 @@
}
TEST_F(NpCppTest, TestLegibleAdvMoveAssignment) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -396,13 +414,13 @@
// move adv2 into adv, the original should be deallocated by assignment
legible2 = std::move(legible);
- ASSERT_EQ(legible2.GetIdentity().GetKind(),
+ ASSERT_EQ(legible2.GetIdentityKind(),
np_ffi::internal::DeserializedV0IdentityKind::Plaintext);
// original result should now be invalid, using it will trigger a use after
// free abort.
ASSERT_DEATH([[maybe_unused]] auto failure =
- legible.GetIdentity(), // NOLINT(bugprone-use-after-move)
+ legible.GetIdentityKind(), // NOLINT(bugprone-use-after-move)
"");
ASSERT_DEATH(
[[maybe_unused]] auto failure = legible.GetNumberOfDataElements(), "");
@@ -411,7 +429,7 @@
// moving again should still lead to an error
auto moved_again = std::move(legible);
ASSERT_DEATH([[maybe_unused]] auto failure = moved_again.IntoPayload(), "");
- ASSERT_DEATH([[maybe_unused]] auto failure = moved_again.GetIdentity(), "");
+ ASSERT_DEATH([[maybe_unused]] auto failure = moved_again.GetIdentityKind(), "");
ASSERT_DEATH([[maybe_unused]] auto failure =
moved_again.GetNumberOfDataElements(),
"");
@@ -426,19 +444,20 @@
}
TEST_F(NpCppTest, V0LegibleAdvUseAfterMove) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto legible_adv = CreateLegibleAdv(book);
// Should be able to use the valid legible adv even though its original parent
// is now out of scope.
- ASSERT_EQ(legible_adv.GetIdentity().GetKind(),
+ ASSERT_EQ(legible_adv.GetIdentityKind(),
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
ASSERT_EQ(legible_adv.GetNumberOfDataElements(), 1);
[[maybe_unused]] auto payload = legible_adv.IntoPayload();
// now that the legible adv has moved into the payload it should no longer be
// valid
- ASSERT_DEATH([[maybe_unused]] auto failure = legible_adv.GetIdentity(), "");
+ ASSERT_DEATH([[maybe_unused]] auto failure = legible_adv.GetIdentityKind(), "");
ASSERT_DEATH([[maybe_unused]] auto failure =
legible_adv.GetNumberOfDataElements(),
"");
@@ -446,16 +465,17 @@
}
TEST_F(NpCppTest, LegibleAdvDestructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
{
auto legible_adv = CreateLegibleAdv(book);
auto legible_adv2 = CreateLegibleAdv(book);
// check that legible advs are valid.
- ASSERT_EQ(legible_adv.GetIdentity().GetKind(),
+ ASSERT_EQ(legible_adv.GetIdentityKind(),
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
ASSERT_EQ(legible_adv.GetNumberOfDataElements(), 1);
- ASSERT_EQ(legible_adv2.GetIdentity().GetKind(),
+ ASSERT_EQ(legible_adv2.GetIdentityKind(),
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
ASSERT_EQ(legible_adv2.GetNumberOfDataElements(), 1);
@@ -480,7 +500,8 @@
}
TEST_F(NpCppTest, V0PayloadDestructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
{
auto payload = CreatePayload(book);
auto payload2 = CreatePayload(book);
@@ -505,7 +526,8 @@
}
TEST_F(NpCppTest, TestV0PayloadMoveConstructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -531,7 +553,8 @@
}
TEST_F(NpCppTest, TestV0PayloadMoveAssignment) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V0AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -562,7 +585,9 @@
}
TEST_F(NpCppTest, InvalidDataElementCast) {
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -574,8 +599,8 @@
ASSERT_EQ(v0_adv.GetKind(),
nearby_protocol::DeserializedV0AdvertisementKind::Legible);
auto legible_adv = v0_adv.IntoLegible();
- auto identity = legible_adv.GetIdentity();
- ASSERT_EQ(identity.GetKind(),
+ auto identity = legible_adv.GetIdentityKind();
+ ASSERT_EQ(identity,
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
auto num_des = legible_adv.GetNumberOfDataElements();
@@ -591,7 +616,9 @@
}
TEST_F(NpCppTest, InvalidDataElementIndex) {
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
nearby_protocol::Deserializer::DeserializeAdvertisement(
@@ -604,8 +631,8 @@
ASSERT_EQ(v0_adv.GetKind(),
nearby_protocol::DeserializedV0AdvertisementKind::Legible);
auto legible_adv = v0_adv.IntoLegible();
- auto identity = legible_adv.GetIdentity();
- ASSERT_EQ(identity.GetKind(),
+ auto identity = legible_adv.GetIdentityKind();
+ ASSERT_EQ(identity,
nearby_protocol::DeserializedV0IdentityKind::Plaintext);
auto num_des = legible_adv.GetNumberOfDataElements();
diff --git a/nearby/presence/np_cpp_ffi/tests/deserialize_v1_tests.cc b/nearby/presence/np_cpp_ffi/tests/deserialize_v1_tests.cc
index f46457e..aa32f7b 100644
--- a/nearby/presence/np_cpp_ffi/tests/deserialize_v1_tests.cc
+++ b/nearby/presence/np_cpp_ffi/tests/deserialize_v1_tests.cc
@@ -19,7 +19,9 @@
#include "gtest/gtest.h"
TEST_F(NpCppTest, V1SimpleTestCase) {
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
auto deserialize_result =
@@ -57,7 +59,8 @@
}
TEST_F(NpCppTest, TestV1AdvMoveConstructor) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V1AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -93,7 +96,8 @@
}
TEST_F(NpCppTest, TestV1AdvMoveAssignment) {
- auto book = nearby_protocol::CredentialBook::TryCreate().value();
+ auto slab = nearby_protocol::CredentialSlab::TryCreate().value();
+ auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value();
auto result = nearby_protocol::Deserializer::DeserializeAdvertisement(
V1AdvSimple, book);
ASSERT_EQ(result.GetKind(),
@@ -153,7 +157,9 @@
}
TEST_F(NpCppTest, TestSectionOwnership) {
- auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate();
+ auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate();
+ ASSERT_TRUE(maybe_credential_slab.ok());
+ auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreateFromSlab(maybe_credential_slab.value());
ASSERT_TRUE(maybe_credential_book.ok());
{
@@ -223,4 +229,4 @@
nearby_protocol::DeserializedV1IdentityKind::Plaintext);
ASSERT_EQ(section2.value().NumberOfDataElements(), 1);
}
-*/
\ No newline at end of file
+*/
diff --git a/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h b/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h
index 4fc20e1..03eb03a 100644
--- a/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h
+++ b/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h
@@ -29,6 +29,7 @@
panic_handler_set = true;
nearby_protocol::GlobalConfig::SetMaxNumDeserializedV0Advertisements(2);
nearby_protocol::GlobalConfig::SetMaxNumDeserializedV1Advertisements(2);
+ nearby_protocol::GlobalConfig::SetMaxNumCredentialSlabs(3);
nearby_protocol::GlobalConfig::SetMaxNumCredentialBooks(2);
} else {
ASSERT_FALSE(
diff --git a/nearby/presence/np_ed25519/Cargo.toml b/nearby/presence/np_ed25519/Cargo.toml
index 601fc82..bd42c65 100644
--- a/nearby/presence/np_ed25519/Cargo.toml
+++ b/nearby/presence/np_ed25519/Cargo.toml
@@ -4,9 +4,12 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
array_view.workspace = true
-crypto_provider = {workspace = true, features = ["raw_private_key_permit"]}
+crypto_provider = { workspace = true, features = ["raw_private_key_permit"] }
sink.workspace = true
tinyvec.workspace = true
diff --git a/nearby/presence/np_ed25519/src/lib.rs b/nearby/presence/np_ed25519/src/lib.rs
index 81a1a10..fe2ab5a 100644
--- a/nearby/presence/np_ed25519/src/lib.rs
+++ b/nearby/presence/np_ed25519/src/lib.rs
@@ -19,10 +19,6 @@
//! or verified. These "context" bytes allow for usage of the
//! same base key-pair for different purposes in the protocol.
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(missing_docs, clippy::indexing_slicing)]
-
-extern crate core;
use array_view::ArrayView;
use crypto_provider::ed25519::{
@@ -191,7 +187,8 @@
impl<C: CryptoProvider> Clone for PublicKey<C> {
fn clone(&self) -> Self {
- Self::from_bytes(&self.to_bytes()).unwrap()
+ #[allow(clippy::expect_used)]
+ Self::from_bytes(&self.to_bytes()).expect("This should always succeed since self will always contain valid public key bytes, which is verified on creation")
}
}
@@ -250,6 +247,7 @@
/// [`SignatureContext#write_length_prefixed`].
fn create_signature_buffer(&self) -> impl Sink<u8> + AsRef<[u8]> {
let mut buffer = ArrayVec::<[u8; MAX_SIGNATURE_BUFFER_LEN]>::new();
+ #[allow(clippy::expect_used)]
self.write_length_prefixed(&mut buffer).expect("Context should always fit into sig buffer");
buffer
}
diff --git a/nearby/presence/np_ffi_core/Cargo.toml b/nearby/presence/np_ffi_core/Cargo.toml
index 126302f..0c14d1c 100644
--- a/nearby/presence/np_ffi_core/Cargo.toml
+++ b/nearby/presence/np_ffi_core/Cargo.toml
@@ -4,12 +4,17 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
array_view.workspace = true
+ldt_np_adv.workspace = true
np_adv = { workspace = true, features = ["alloc"] }
+np_hkdf.workspace = true
handle_map.workspace = true
crypto_provider.workspace = true
-crypto_provider_default = {workspace = true, default-features = false}
+crypto_provider_default = { workspace = true, default-features = false }
lock_adapter.workspace = true
lazy_static.workspace = true
diff --git a/nearby/presence/np_ffi_core/src/common.rs b/nearby/presence/np_ffi_core/src/common.rs
index 1683b68..6333db5 100644
--- a/nearby/presence/np_ffi_core/src/common.rs
+++ b/nearby/presence/np_ffi_core/src/common.rs
@@ -40,6 +40,11 @@
/// - In all other cases, 16 shards will be used by default.
num_shards: u8,
+ /// The maximum number of credential slabs which may be active
+ /// at any one time. By default, this value will be set to
+ /// `u32::MAX - 1`, which is the upper-bound on this value.
+ max_num_credential_slabs: u32,
+
/// The maximum number of credential books which may be active
/// at any one time. By default, this value will be set to
/// `u32::MAX - 1`, which is the upper-bound on this value.
@@ -68,6 +73,7 @@
pub(crate) const fn new() -> Self {
Self {
num_shards: 0,
+ max_num_credential_slabs: DEFAULT_MAX_HANDLES,
max_num_credential_books: DEFAULT_MAX_HANDLES,
max_num_deserialized_v0_advertisements: DEFAULT_MAX_HANDLES,
max_num_deserialized_v1_advertisements: DEFAULT_MAX_HANDLES,
@@ -92,6 +98,9 @@
self.num_shards
}
}
+ pub(crate) fn max_num_credential_slabs(&self) -> u32 {
+ self.max_num_credential_slabs
+ }
pub(crate) fn max_num_credential_books(&self) -> u32 {
self.max_num_credential_books
}
@@ -112,6 +121,13 @@
self.max_num_credential_books = DEFAULT_MAX_HANDLES.min(max_num_credential_books)
}
+ /// Sets the maximum number of active handles to credential-slabs
+ /// which may be active at any one time.
+ /// Max value: `u32::MAX - 1`.
+ pub fn set_max_num_credential_slabs(&mut self, max_num_credential_slabs: u32) {
+ self.max_num_credential_slabs = DEFAULT_MAX_HANDLES.min(max_num_credential_slabs)
+ }
+
/// Sets the maximum number of active handles to deserialized v0
/// advertisements which may be active at any one time.
/// Max value: `u32::MAX - 1`.
@@ -140,6 +156,9 @@
pub(crate) fn global_num_shards() -> u8 {
COMMON_CONFIG.read().num_shards()
}
+pub(crate) fn global_max_num_credential_slabs() -> u32 {
+ COMMON_CONFIG.read().max_num_credential_slabs()
+}
pub(crate) fn global_max_num_credential_books() -> u32 {
COMMON_CONFIG.read().max_num_credential_books()
}
@@ -169,6 +188,17 @@
config.set_num_shards(num_shards);
}
+/// Sets the maximum number of active handles to credential slabs
+/// which may be active at any one time. Max value: `u32::MAX - 1`.
+///
+/// Setting this value will have no effect if the handle-maps for the
+/// API have already begun being used by the client code, and any
+/// values set will take effect upon the first usage of any API
+/// call utilizing credential slabs.
+pub fn global_config_set_max_num_credential_slabs(max_num_credential_slabs: u32) {
+ let mut config = COMMON_CONFIG.write();
+ config.set_max_num_credential_slabs(max_num_credential_slabs);
+}
/// Sets the maximum number of active handles to credential books
/// which may be active at any one time. Max value: `u32::MAX - 1`.
///
@@ -275,6 +305,32 @@
}
}
+/// The DE type for an encrypted identity
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum EncryptedIdentityType {
+ /// Identity for broadcasts to nearby devices with the same
+ /// logged-in-account (for some account).
+ Private = 1,
+ /// Identity for broadcasts to nearby devices which this
+ /// device has declared to trust.
+ Trusted = 2,
+ /// Identity for broadcasts to devices which have been provisioned
+ /// offline with this device.
+ Provisioned = 4,
+}
+
+impl From<np_adv::de_type::EncryptedIdentityDataElementType> for EncryptedIdentityType {
+ fn from(value: np_adv::de_type::EncryptedIdentityDataElementType) -> Self {
+ use np_adv::de_type::EncryptedIdentityDataElementType;
+ match value {
+ EncryptedIdentityDataElementType::Private => Self::Private,
+ EncryptedIdentityDataElementType::Trusted => Self::Trusted,
+ EncryptedIdentityDataElementType::Provisioned => Self::Provisioned,
+ }
+ }
+}
+
/// Error raised when attempting to cast an enum to
/// one of its variants, but the value is actually
/// of a different variant than the requested one.
diff --git a/nearby/presence/np_ffi_core/src/credentials.rs b/nearby/presence/np_ffi_core/src/credentials.rs
index 5392417..0972d45 100644
--- a/nearby/presence/np_ffi_core/src/credentials.rs
+++ b/nearby/presence/np_ffi_core/src/credentials.rs
@@ -14,13 +14,282 @@
//! Credential-related data-types and functions
use crate::common::*;
-use crate::utils::FfiEnum;
-use handle_map::{declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError};
+use crate::utils::{FfiEnum, LocksLongerThan};
+use crypto_provider_default::CryptoProviderImpl;
+use handle_map::{
+ declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError,
+ HandleMapTryAllocateError,
+};
+use std::sync::Arc;
+
+/// Cryptographic information about a particular V0 discovery credential
+/// necessary to match and decrypt encrypted V0 advertisements.
+#[repr(C)]
+pub struct V0DiscoveryCredential {
+ key_seed: [u8; 32],
+ legacy_metadata_key_hmac: [u8; 32],
+}
+
+impl V0DiscoveryCredential {
+ /// Constructs a new V0 discovery credential with the given 32-byte key-seed
+ /// and the given 32-byte HMAC for the (14-byte) legacy metadata key.
+ pub fn new(key_seed: [u8; 32], legacy_metadata_key_hmac: [u8; 32]) -> Self {
+ Self { key_seed, legacy_metadata_key_hmac }
+ }
+ fn into_internal(self) -> np_adv::credential::v0::V0DiscoveryCredential {
+ np_adv::credential::v0::V0DiscoveryCredential::new(
+ self.key_seed,
+ self.legacy_metadata_key_hmac,
+ )
+ }
+}
+
+/// Cryptographic information about a particular V1 discovery credential
+/// necessary to match and decrypt encrypted V1 advertisement sections.
+#[repr(C)]
+pub struct V1DiscoveryCredential {
+ key_seed: [u8; 32],
+ expected_unsigned_metadata_key_hmac: [u8; 32],
+ expected_signed_metadata_key_hmac: [u8; 32],
+ pub_key: [u8; 32],
+}
+
+impl V1DiscoveryCredential {
+ /// Constructs a new V1 discovery credential with the given 32-byte key-seed,
+ /// unsigned-variant HMAC of the metadata key, the signed-variant HMAC of
+ /// the metadata key, and the given public key for signature verification.
+ pub fn new(
+ key_seed: [u8; 32],
+ expected_unsigned_metadata_key_hmac: [u8; 32],
+ expected_signed_metadata_key_hmac: [u8; 32],
+ pub_key: [u8; 32],
+ ) -> Self {
+ Self {
+ key_seed,
+ expected_unsigned_metadata_key_hmac,
+ expected_signed_metadata_key_hmac,
+ pub_key,
+ }
+ }
+ fn into_internal(self) -> np_adv::credential::v1::V1DiscoveryCredential {
+ np_adv::credential::v1::V1DiscoveryCredential::new(
+ self.key_seed,
+ self.expected_unsigned_metadata_key_hmac,
+ self.expected_signed_metadata_key_hmac,
+ self.pub_key,
+ )
+ }
+}
+
+/// A [`MatchedCredential`] implementation for the purpose of
+/// capturing match-data details across the FFI boundary.
+/// Since we can't know what plaintext match-data the client
+/// wants to keep around, we just expose an ID for them to do
+/// their own look-up.
+///
+/// For the encrypted metadata, we need a slightly richer
+/// representation, since we need to be able to decrypt
+/// the metadata as part of an API call. Internally, we
+/// keep this as an atomic-reference-counted pointer to
+/// a byte array, and never expose this raw pointer across
+/// the FFI boundary.
+#[derive(Debug, Clone)]
+pub struct MatchedCredential {
+ cred_id: u32,
+ encrypted_metadata_bytes: Arc<[u8]>,
+}
+
+impl MatchedCredential {
+ /// Constructs a new matched credential from the given match-id
+ /// (some arbitrary `u32` identifier) and encrypted metadata bytes,
+ /// copied from the given slice.
+ pub fn new(cred_id: u32, encrypted_metadata_bytes: &[u8]) -> Self {
+ let encrypted_metadata_bytes = encrypted_metadata_bytes.to_vec().into_boxed_slice();
+ let encrypted_metadata_bytes = Arc::from(encrypted_metadata_bytes);
+ Self { cred_id, encrypted_metadata_bytes }
+ }
+ /// Gets the pre-specified numerical identifier for this matched-credential.
+ pub(crate) fn id(&self) -> u32 {
+ self.cred_id
+ }
+}
+
+impl PartialEq<MatchedCredential> for MatchedCredential {
+ fn eq(&self, other: &Self) -> bool {
+ self.id() == other.id()
+ }
+}
+
+impl Eq for MatchedCredential {}
+
+impl np_adv::credential::MatchedCredential for MatchedCredential {
+ type EncryptedMetadata = Arc<[u8]>;
+ type EncryptedMetadataFetchError = core::convert::Infallible;
+ fn fetch_encrypted_metadata(&self) -> Result<Arc<[u8]>, core::convert::Infallible> {
+ Ok(self.encrypted_metadata_bytes.clone())
+ }
+}
+
+/// Internals of a credential slab,
+/// an intermediate used in the construction
+/// of a credential-book.
+pub struct CredentialSlabInternals {
+ v0_creds:
+ Vec<np_adv::credential::MatchableCredential<np_adv::credential::v0::V0, MatchedCredential>>,
+ v1_creds:
+ Vec<np_adv::credential::MatchableCredential<np_adv::credential::v1::V1, MatchedCredential>>,
+}
+
+impl CredentialSlabInternals {
+ pub(crate) fn new() -> Self {
+ Self { v0_creds: Vec::new(), v1_creds: Vec::new() }
+ }
+ /// Adds the given V0 discovery credential with the given
+ /// identity match-data onto the end of the V0 credentials
+ /// currently stored in this slab.
+ pub(crate) fn add_v0(
+ &mut self,
+ discovery_credential: V0DiscoveryCredential,
+ match_data: MatchedCredential,
+ ) {
+ let discovery_credential = discovery_credential.into_internal();
+ let matchable_credential =
+ np_adv::credential::MatchableCredential { discovery_credential, match_data };
+ self.v0_creds.push(matchable_credential);
+ }
+ /// Adds the given V1 discovery credential with the given
+ /// identity match-data onto the end of the V1 credentials
+ /// currently stored in this slab.
+ pub(crate) fn add_v1(
+ &mut self,
+ discovery_credential: V1DiscoveryCredential,
+ match_data: MatchedCredential,
+ ) {
+ let discovery_credential = discovery_credential.into_internal();
+ let matchable_credential =
+ np_adv::credential::MatchableCredential { discovery_credential, match_data };
+ self.v1_creds.push(matchable_credential);
+ }
+}
+
+/// Discriminant for `CreateCredentialSlabResult`
+#[repr(u8)]
+pub enum CreateCredentialSlabResultKind {
+ /// There was no space left to create a new credential slab
+ NoSpaceLeft = 0,
+ /// We created a new credential slab behind the given handle.
+ /// The associated payload may be obtained via
+ /// `CreateCredentialSlabResult#into_success()`.
+ Success = 1,
+}
+
+/// Result type for `create_credential_slab`
+#[repr(C)]
+#[allow(missing_docs)]
+pub enum CreateCredentialSlabResult {
+ NoSpaceLeft,
+ Success(CredentialSlab),
+}
+
+impl From<Result<CredentialSlab, HandleMapFullError>> for CreateCredentialSlabResult {
+ fn from(result: Result<CredentialSlab, HandleMapFullError>) -> Self {
+ match result {
+ Ok(slab) => CreateCredentialSlabResult::Success(slab),
+ Err(_) => CreateCredentialSlabResult::NoSpaceLeft,
+ }
+ }
+}
+
+/// Result type for trying to add a credential to a credential-slab.
+#[repr(u8)]
+pub enum AddCredentialToSlabResult {
+ /// We succeeded in adding the credential to the slab.
+ Success = 0,
+ /// The handle to the slab was actually invalid.
+ InvalidHandle = 1,
+}
+
+declare_handle_map! {
+ mod credential_slab {
+ #[dimensions = super::get_credential_slab_handle_map_dimensions()]
+ type CredentialSlab: HandleLike<Object = super::CredentialSlabInternals>;
+ }
+}
+use credential_slab::CredentialSlab;
+
+fn get_credential_slab_handle_map_dimensions() -> HandleMapDimensions {
+ HandleMapDimensions {
+ num_shards: global_num_shards(),
+ max_active_handles: global_max_num_credential_slabs(),
+ }
+}
+
+impl CredentialSlab {
+ /// Adds the given V0 discovery credential with some associated
+ /// match-data to this credential slab.
+ pub fn add_v0(
+ &self,
+ discovery_credential: V0DiscoveryCredential,
+ match_data: MatchedCredential,
+ ) -> AddCredentialToSlabResult {
+ match self.get_mut() {
+ Ok(mut write_guard) => {
+ write_guard.add_v0(discovery_credential, match_data);
+ AddCredentialToSlabResult::Success
+ }
+ Err(_) => AddCredentialToSlabResult::InvalidHandle,
+ }
+ }
+ /// Adds the given V1 discovery credential with some associated
+ /// match-data to this credential slab.
+ pub fn add_v1(
+ &self,
+ discovery_credential: V1DiscoveryCredential,
+ match_data: MatchedCredential,
+ ) -> AddCredentialToSlabResult {
+ match self.get_mut() {
+ Ok(mut write_guard) => {
+ write_guard.add_v1(discovery_credential, match_data);
+ AddCredentialToSlabResult::Success
+ }
+ Err(_) => AddCredentialToSlabResult::InvalidHandle,
+ }
+ }
+}
+
+/// Allocates a new credential-slab, returning a handle to the created object
+pub fn create_credential_slab() -> CreateCredentialSlabResult {
+ CredentialSlab::allocate(CredentialSlabInternals::new).into()
+}
+
+impl FfiEnum for CreateCredentialSlabResult {
+ type Kind = CreateCredentialSlabResultKind;
+ fn kind(&self) -> Self::Kind {
+ match self {
+ CreateCredentialSlabResult::NoSpaceLeft => CreateCredentialSlabResultKind::NoSpaceLeft,
+ CreateCredentialSlabResult::Success(_) => CreateCredentialSlabResultKind::Success,
+ }
+ }
+}
+
+impl CreateCredentialSlabResult {
+ declare_enum_cast! {into_success, Success, CredentialSlab }
+}
/// Internal, Rust-side implementation of a credential-book.
/// See [`CredentialBook`] for the FFI-side handles.
-// TODO: Give this a real definition!
-pub struct CredentialBookInternals;
+pub struct CredentialBookInternals {
+ pub(crate) book: np_adv::credential::book::PrecalculatedOwnedCredentialBook<MatchedCredential>,
+}
+
+impl CredentialBookInternals {
+ fn create_from_slab(credential_slab: CredentialSlabInternals) -> Self {
+ let book = np_adv::credential::book::CredentialBookBuilder::build_precalculated_owned_book::<
+ CryptoProviderImpl,
+ >(credential_slab.v0_creds, credential_slab.v1_creds);
+ Self { book }
+ }
+}
fn get_credential_book_handle_map_dimensions() -> HandleMapDimensions {
HandleMapDimensions {
@@ -40,42 +309,60 @@
/// Discriminant for `CreateCredentialBookResult`
#[repr(u8)]
pub enum CreateCredentialBookResultKind {
- /// There was no space left to create a new credential book
- NoSpaceLeft = 0,
/// We created a new credential book behind the given handle.
/// The associated payload may be obtained via
/// `CreateCredentialBookResult#into_success()`.
- Success = 1,
+ Success = 0,
+ /// There was no space left to create a new credential book
+ NoSpaceLeft = 1,
+ /// The slab that we tried to create a credential-book from
+ /// actually was an invalid handle.
+ InvalidSlabHandle = 2,
}
/// Result type for `create_credential_book`
#[repr(u8)]
#[allow(missing_docs)]
pub enum CreateCredentialBookResult {
- NoSpaceLeft = 0,
- Success(CredentialBook) = 1,
+ Success(CredentialBook) = 0,
+ NoSpaceLeft = 1,
+ InvalidSlabHandle = 2,
}
-impl From<Result<CredentialBook, HandleMapFullError>> for CreateCredentialBookResult {
- fn from(result: Result<CredentialBook, HandleMapFullError>) -> Self {
- match result {
- Ok(book) => CreateCredentialBookResult::Success(book),
- Err(_) => CreateCredentialBookResult::NoSpaceLeft,
- }
- }
-}
+impl LocksLongerThan<CredentialSlab> for CredentialBook {}
/// Allocates a new credential-book, returning a handle to the created object
-pub fn create_credential_book() -> CreateCredentialBookResult {
- CredentialBook::allocate(|| CredentialBookInternals).into()
+pub fn create_credential_book_from_slab(
+ credential_slab: CredentialSlab,
+) -> CreateCredentialBookResult {
+ // The credential-book allocation is on the outside, since we should ensure
+ // that we have a slot available for construction before we try to deallocate
+ // the credential-slab which was passed in.
+ let op_result = CredentialBook::try_allocate(|| {
+ credential_slab.deallocate().map(CredentialBookInternals::create_from_slab)
+ });
+ match op_result {
+ Ok(book) => CreateCredentialBookResult::Success(book),
+ Err(HandleMapTryAllocateError::ValueProviderFailed(_)) => {
+ // Unable to deallocate the referenced credential-slab
+ CreateCredentialBookResult::InvalidSlabHandle
+ }
+ Err(HandleMapTryAllocateError::HandleMapFull) => {
+ // Unable to allocate space for a new credential-book
+ CreateCredentialBookResult::NoSpaceLeft
+ }
+ }
}
impl FfiEnum for CreateCredentialBookResult {
type Kind = CreateCredentialBookResultKind;
fn kind(&self) -> Self::Kind {
match self {
- CreateCredentialBookResult::NoSpaceLeft => CreateCredentialBookResultKind::NoSpaceLeft,
CreateCredentialBookResult::Success(_) => CreateCredentialBookResultKind::Success,
+ CreateCredentialBookResult::NoSpaceLeft => CreateCredentialBookResultKind::NoSpaceLeft,
+ CreateCredentialBookResult::InvalidSlabHandle => {
+ CreateCredentialBookResultKind::InvalidSlabHandle
+ }
}
}
}
@@ -89,5 +376,7 @@
credential_book.deallocate().map(|_| ()).into()
}
-/// A handle on a particular v0 shared credential stored within a credential book
-pub struct V0SharedCredential;
+/// Deallocates a credential-slab by its handle
+pub fn deallocate_credential_slab(credential_slab: CredentialSlab) -> DeallocateResult {
+ credential_slab.deallocate().map(|_| ()).into()
+}
diff --git a/nearby/presence/np_ffi_core/src/deserialize/mod.rs b/nearby/presence/np_ffi_core/src/deserialize/mod.rs
index 38f59ba..44510f6 100644
--- a/nearby/presence/np_ffi_core/src/deserialize/mod.rs
+++ b/nearby/presence/np_ffi_core/src/deserialize/mod.rs
@@ -112,16 +112,13 @@
credential_book: CredentialBook,
) -> Result<DeserializeAdvertisementSuccess, DeserializeAdvertisementError> {
// Deadlock Safety: Credential-book locks always live longer than deserialized advs.
- let _credential_book_read_guard = credential_book.get()?;
+ let credential_book_read_guard = credential_book.get()?;
- //TODO: Use an actual credential source
- let cred_book = np_adv::credential::book::CredentialBookBuilder::<
- np_adv::credential::EmptyMatchedCredential,
- >::build_cached_slice_book::<0, 0, CryptoProviderImpl>(&[], &[]);
+ let cred_book = &credential_book_read_guard.book;
let arena = deserialization_arena!();
let deserialized_advertisement =
- np_adv::deserialize_advertisement::<_, CryptoProviderImpl>(arena, adv_payload, &cred_book)?;
+ np_adv::deserialize_advertisement::<_, CryptoProviderImpl>(arena, adv_payload, cred_book)?;
match deserialized_advertisement {
np_adv::DeserializedAdvertisement::V0(adv_contents) => {
let adv_handle = DeserializedV0Advertisement::allocate_with_contents(adv_contents)?;
@@ -156,3 +153,13 @@
) -> DeserializeAdvertisementResult {
deserialize_advertisement_from_slice(adv_payload.as_slice(), credential_book)
}
+
+/// Errors returned from [`crate::deserialize::v0::v0_payload::V0Payload#decrypt_metadata`].
+pub enum DecryptMetadataError {
+ /// The advertisement payload handle was either deallocated
+ /// or corresponds to a public advertisement, and so we
+ /// don't have any metadata to decrypt.
+ EncryptedMetadataNotAvailable,
+ /// Decryption of the raw metadata bytes failed.
+ DecryptionFailed,
+}
diff --git a/nearby/presence/np_ffi_core/src/deserialize/v0.rs b/nearby/presence/np_ffi_core/src/deserialize/v0.rs
index d8c008a..a07b9d8 100644
--- a/nearby/presence/np_ffi_core/src/deserialize/v0.rs
+++ b/nearby/presence/np_ffi_core/src/deserialize/v0.rs
@@ -15,10 +15,14 @@
use crate::common::*;
use crate::credentials::credential_book::CredentialBook;
+use crate::credentials::MatchedCredential;
+use crate::deserialize::DecryptMetadataError;
use crate::utils::{FfiEnum, LocksLongerThan};
+use crypto_provider_default::CryptoProviderImpl;
use handle_map::{declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError};
use np_adv::legacy::actions::ActionsDataElement;
use np_adv::legacy::{data_elements as np_adv_de, Ciphertext, PacketFlavorEnum, Plaintext};
+use np_adv::HasIdentityMatch;
use std::vec::Vec;
/// Discriminant for possible results of V0 advertisement deserialization
@@ -66,8 +70,10 @@
}
}
- pub(crate) fn allocate_with_contents<M: np_adv::credential::MatchedCredential>(
- contents: np_adv::V0AdvertisementContents<M>,
+ pub(crate) fn allocate_with_contents(
+ contents: np_adv::V0AdvertisementContents<
+ np_adv::credential::ReferencedMatchedCredential<MatchedCredential>,
+ >,
) -> Result<Self, DeserializeAdvertisementError> {
match contents {
np_adv::V0AdvertisementContents::Plaintext(plaintext_contents) => {
@@ -76,8 +82,12 @@
)?;
Ok(Self::Legible(adv))
}
- np_adv::V0AdvertisementContents::Decrypted(_) => {
- unimplemented!();
+ np_adv::V0AdvertisementContents::Decrypted(decrypted_contents) => {
+ let decrypted_contents = decrypted_contents.clone_match_data();
+ let adv = LegibleDeserializedV0Advertisement::allocate_with_decrypted_contents(
+ decrypted_contents,
+ )?;
+ Ok(Self::Legible(adv))
}
np_adv::V0AdvertisementContents::NoMatchingCredentials => {
Ok(Self::NoMatchingCredentials)
@@ -93,7 +103,7 @@
pub struct LegibleDeserializedV0Advertisement {
num_des: u8,
payload: V0Payload,
- identity: DeserializedV0Identity,
+ identity_kind: DeserializedV0IdentityKind,
}
impl LegibleDeserializedV0Advertisement {
@@ -105,8 +115,38 @@
.collect::<Result<Vec<_>, _>>()
.map_err(|_| DeserializeAdvertisementError)?;
let num_des = data_elements.len() as u8;
- let payload = V0Payload::allocate_with_data_elements(data_elements)?;
- Ok(Self { num_des, payload, identity: DeserializedV0Identity::Plaintext })
+ let payload = V0Payload::allocate_with_plaintext_data_elements(data_elements)?;
+ Ok(Self { num_des, payload, identity_kind: DeserializedV0IdentityKind::Plaintext })
+ }
+ pub(crate) fn allocate_with_decrypted_contents(
+ contents: np_adv::WithMatchedCredential<
+ MatchedCredential,
+ np_adv::legacy::deserialize::DecryptedAdvContents,
+ >,
+ ) -> Result<Self, DeserializeAdvertisementError> {
+ let data_elements = contents
+ .contents()
+ .data_elements()
+ .collect::<Result<Vec<_>, _>>()
+ .map_err(|_| DeserializeAdvertisementError)?;
+ let num_des = data_elements.len() as u8;
+
+ let salt = contents.contents().salt();
+ let identity_type = contents.contents().identity_type();
+
+ // Reduce the information contained in the contents to just
+ // the metadata key, since we're done copying over the DEs
+ // and other data into an FFI-friendly form.
+ let match_data = contents.map(|x| x.metadata_key());
+
+ let payload = V0Payload::allocate_with_decrypted_contents(
+ identity_type,
+ salt,
+ match_data,
+ data_elements,
+ )?;
+
+ Ok(Self { num_des, payload, identity_kind: DeserializedV0IdentityKind::Decrypted })
}
/// Gets the number of data-elements in this adv's payload
/// Suitable as an iteration bound for `Self.into_payload().get_de(...)`.
@@ -117,9 +157,10 @@
pub fn payload(&self) -> V0Payload {
self.payload
}
- /// Destructures this legible advertisement into just the identity information
- pub fn identity(&self) -> DeserializedV0Identity {
- self.identity
+ /// Destructures this legible advertisement into just the discriminant
+ /// for the kind of identity (plaintext/encrypted) used for its contents.
+ pub fn identity_kind(&self) -> DeserializedV0IdentityKind {
+ self.identity_kind
}
/// Deallocates the underlying handle of the payload
pub fn deallocate(self) -> DeallocateResult {
@@ -127,7 +168,8 @@
}
}
-/// Discriminant for `DeserializedV0Identity`.
+/// Discriminant for deserialized information about the V0
+/// identity utilized by a deserialized V0 advertisement.
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum DeserializedV0IdentityKind {
@@ -137,30 +179,136 @@
Decrypted = 1,
}
-/// Represents deserialized information about the V0 identity utilized
-/// by a deserialized V0 advertisement
+/// Information about the identity which matched a
+/// decrypted V0 advertisement.
+#[derive(Clone, Copy)]
#[repr(C)]
-#[allow(missing_docs)]
-#[derive(Copy, Clone, Eq, PartialEq)]
-pub enum DeserializedV0Identity {
- Plaintext,
- // TODO: This gets a payload once we support creds
- Decrypted,
+pub struct DeserializedV0IdentityDetails {
+ /// The identity type (private/provisioned/trusted)
+ identity_type: EncryptedIdentityType,
+ /// The ID of the credential which
+ /// matched the deserialized adv
+ cred_id: u32,
+ /// The 14-byte legacy metadata key
+ metadata_key: [u8; 14],
+ /// The 2-byte advertisement salt
+ salt: [u8; 2],
}
-impl FfiEnum for DeserializedV0Identity {
- type Kind = DeserializedV0IdentityKind;
+impl DeserializedV0IdentityDetails {
+ pub(crate) fn new(
+ cred_id: u32,
+ identity_type: np_adv::de_type::EncryptedIdentityDataElementType,
+ salt: ldt_np_adv::LegacySalt,
+ metadata_key: np_adv::legacy::ShortMetadataKey,
+ ) -> Self {
+ let metadata_key = metadata_key.0;
+ let salt = *salt.bytes();
+ let identity_type = identity_type.into();
+ Self { identity_type, cred_id, salt, metadata_key }
+ }
+ /// Returns the ID of the credential which
+ /// matched the deserialized adv
+ pub fn cred_id(&self) -> u32 {
+ self.cred_id
+ }
+ /// Returns the identity type (private/provisioned/trusted)
+ pub fn identity_type(&self) -> EncryptedIdentityType {
+ self.identity_type
+ }
+ /// Returns the 14-byte legacy metadata key
+ pub fn metadata_key(&self) -> [u8; 14] {
+ self.metadata_key
+ }
+ /// Returns the 2-byte advertisement salt
+ pub fn salt(&self) -> [u8; 2] {
+ self.salt
+ }
+}
+
+/// Discriminant for `GetV0IdentityDetailsResult`
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum GetV0IdentityDetailsResultKind {
+ /// The attempt to get the identity details
+ /// for the advertisement failed, possibly
+ /// due to the advertisement being a public
+ /// advertisement, or the underlying
+ /// advertisement has already been deallocated.
+ Error = 0,
+ /// The attempt to get the identity details succeeded.
+ /// The wrapped identity details may be obtained via
+ /// `GetV0IdentityDetailsResult#into_success`.
+ Success = 1,
+}
+
+/// The result of attempting to get the identity details
+/// for a V0 advertisement via
+/// `DeserializedV0Advertisement#get_identity_details`.
+#[repr(C)]
+#[allow(missing_docs)]
+pub enum GetV0IdentityDetailsResult {
+ Error,
+ Success(DeserializedV0IdentityDetails),
+}
+
+impl FfiEnum for GetV0IdentityDetailsResult {
+ type Kind = GetV0IdentityDetailsResultKind;
fn kind(&self) -> Self::Kind {
match self {
- DeserializedV0Identity::Plaintext => DeserializedV0IdentityKind::Plaintext,
- DeserializedV0Identity::Decrypted => DeserializedV0IdentityKind::Decrypted,
+ GetV0IdentityDetailsResult::Error => GetV0IdentityDetailsResultKind::Error,
+ GetV0IdentityDetailsResult::Success(_) => GetV0IdentityDetailsResultKind::Success,
}
}
}
+impl GetV0IdentityDetailsResult {
+ declare_enum_cast! {into_success, Success, DeserializedV0IdentityDetails}
+}
+
+/// Internal implementation of a deserialized V0 identity.
+pub(crate) struct DeserializedV0IdentityInternals {
+ /// The details about the identity, suitable
+ /// for direct communication over FFI
+ details: DeserializedV0IdentityDetails,
+ /// The metadata key, together with the matched
+ /// credential and enough information to decrypt
+ /// the credential metadata, if desired.
+ match_data: np_adv::WithMatchedCredential<MatchedCredential, np_adv::legacy::ShortMetadataKey>,
+}
+
+impl DeserializedV0IdentityInternals {
+ pub(crate) fn new(
+ identity_type: np_adv::de_type::EncryptedIdentityDataElementType,
+ salt: ldt_np_adv::LegacySalt,
+ match_data: np_adv::WithMatchedCredential<
+ MatchedCredential,
+ np_adv::legacy::ShortMetadataKey,
+ >,
+ ) -> Self {
+ let cred_id = match_data.matched_credential().id();
+ let metadata_key = match_data.contents();
+ let details =
+ DeserializedV0IdentityDetails::new(cred_id, identity_type, salt, *metadata_key);
+ Self { details, match_data }
+ }
+ /// Gets the directly-transmissible details about
+ /// this deserialized V0 identity. Does not include
+ /// decrypted metadata bytes.
+ pub(crate) fn details(&self) -> DeserializedV0IdentityDetails {
+ self.details
+ }
+ /// Attempts to decrypt the metadata associated
+ /// with this identity.
+ pub(crate) fn decrypt_metadata(&self) -> Option<Vec<u8>> {
+ self.match_data.decrypt_metadata::<CryptoProviderImpl>().ok()
+ }
+}
+
/// The internal data-structure used for storing
/// the payload of a deserialized V0 advertisement.
pub struct V0PayloadInternals {
+ identity: Option<DeserializedV0IdentityInternals>,
des: Vec<V0DataElement>,
}
@@ -173,6 +321,24 @@
None => GetV0DEResult::Error,
}
}
+ /// Gets the identity details for this V0 payload,
+ /// if this payload was associated with an identity.
+ fn get_identity_details(&self) -> GetV0IdentityDetailsResult {
+ match &self.identity {
+ Some(x) => GetV0IdentityDetailsResult::Success(x.details()),
+ None => GetV0IdentityDetailsResult::Error,
+ }
+ }
+ /// Attempts to decrypt the metadata for the matched
+ /// credential for this V0 payload (if any)
+ fn decrypt_metadata(&self) -> Result<Vec<u8>, DecryptMetadataError> {
+ match &self.identity {
+ None => Err(DecryptMetadataError::EncryptedMetadataNotAvailable),
+ Some(identity) => {
+ identity.decrypt_metadata().ok_or(DecryptMetadataError::DecryptionFailed)
+ }
+ }
+ }
}
fn get_v0_payload_handle_map_dimensions() -> HandleMapDimensions {
@@ -195,12 +361,33 @@
impl LocksLongerThan<V0Payload> for CredentialBook {}
impl V0Payload {
- pub(crate) fn allocate_with_data_elements<F: np_adv::legacy::PacketFlavor>(
- data_elements: Vec<np_adv::legacy::deserialize::PlainDataElement<F>>,
+ pub(crate) fn allocate_with_plaintext_data_elements(
+ data_elements: Vec<
+ np_adv::legacy::deserialize::PlainDataElement<np_adv::legacy::Plaintext>,
+ >,
) -> Result<Self, HandleMapFullError> {
Self::allocate(move || {
let des = data_elements.into_iter().map(V0DataElement::from).collect();
- V0PayloadInternals { des }
+ let identity = None;
+ V0PayloadInternals { des, identity }
+ })
+ }
+ pub(crate) fn allocate_with_decrypted_contents(
+ identity_type: np_adv::de_type::EncryptedIdentityDataElementType,
+ salt: ldt_np_adv::LegacySalt,
+ match_data: np_adv::WithMatchedCredential<
+ MatchedCredential,
+ np_adv::legacy::ShortMetadataKey,
+ >,
+ data_elements: Vec<
+ np_adv::legacy::deserialize::PlainDataElement<np_adv::legacy::Ciphertext>,
+ >,
+ ) -> Result<Self, HandleMapFullError> {
+ Self::allocate(move || {
+ let des = data_elements.into_iter().map(V0DataElement::from).collect();
+ let identity =
+ Some(DeserializedV0IdentityInternals::new(identity_type, salt, match_data));
+ V0PayloadInternals { des, identity }
})
}
/// Gets the data-element with the given index in this v0 adv payload
@@ -211,6 +398,32 @@
}
}
+ /// Gets the identity details for this V0 payload,
+ /// if this payload was associted with an identity
+ /// (i.e: non-public advertisements).
+ pub fn get_identity_details(&self) -> GetV0IdentityDetailsResult {
+ match self.get() {
+ Ok(read_guard) => read_guard.get_identity_details(),
+ Err(_) => GetV0IdentityDetailsResult::Error,
+ }
+ }
+
+ /// Attempts to decrypt the metadata for the matched
+ /// credential for this V0 payload (if any)
+ ///
+ /// Note that while this method is publicly exposed
+ /// from `np_ffi_core`, since it involves the (FFI-layer-unexpressed)
+ /// type `Vec<u8>`, a direct wrapper will not suffice,
+ /// and instead a language-specific binding will need to
+ /// be generated for this method which respects the
+ /// expected memory-management semantics of the target language.
+ pub fn decrypt_metadata(&self) -> Result<Vec<u8>, DecryptMetadataError> {
+ match self.get() {
+ Ok(read_guard) => read_guard.decrypt_metadata(),
+ Err(_) => Err(DecryptMetadataError::EncryptedMetadataNotAvailable),
+ }
+ }
+
/// Deallocates any underlying data held by a V0Payload
pub fn deallocate_payload(&self) -> DeallocateResult {
self.deallocate().map(|_| ()).into()
diff --git a/nearby/presence/np_ffi_core/src/deserialize/v1.rs b/nearby/presence/np_ffi_core/src/deserialize/v1.rs
index 819bb8c..4684f55 100644
--- a/nearby/presence/np_ffi_core/src/deserialize/v1.rs
+++ b/nearby/presence/np_ffi_core/src/deserialize/v1.rs
@@ -16,11 +16,15 @@
use super::DeserializeAdvertisementError;
use crate::common::*;
use crate::credentials::credential_book::CredentialBook;
+use crate::credentials::MatchedCredential;
+use crate::deserialize::DecryptMetadataError;
use crate::utils::*;
use array_view::ArrayView;
+use crypto_provider_default::CryptoProviderImpl;
use handle_map::{declare_handle_map, HandleLike, HandleMapDimensions};
use legible_v1_sections::LegibleV1Sections;
use np_adv::extended::deserialize::DataElementParseError;
+use np_adv::HasIdentityMatch;
use std::vec::Vec;
/// Representation of a deserialized V1 advertisement
@@ -59,8 +63,10 @@
self.legible_sections.deallocate().map(|_| ()).into()
}
- pub(crate) fn allocate_with_contents<M: np_adv::credential::MatchedCredential>(
- contents: np_adv::V1AdvertisementContents<M>,
+ pub(crate) fn allocate_with_contents(
+ contents: np_adv::V1AdvertisementContents<
+ np_adv::credential::ReferencedMatchedCredential<MatchedCredential>,
+ >,
) -> Result<Self, DeserializeAdvertisementError> {
// 16-section limit enforced by np_adv
let num_undecryptable_sections = contents.invalid_sections_count() as u8;
@@ -109,13 +115,25 @@
}
}
-impl<'adv, M: np_adv::credential::MatchedCredential>
- TryFrom<Vec<np_adv::V1DeserializedSection<'adv, M>>> for LegibleV1SectionsInternals
+impl<'adv>
+ TryFrom<
+ Vec<
+ np_adv::V1DeserializedSection<
+ 'adv,
+ np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>,
+ >,
+ >,
+ > for LegibleV1SectionsInternals
{
type Error = DataElementParseError;
fn try_from(
- contents: Vec<np_adv::V1DeserializedSection<'adv, M>>,
+ contents: Vec<
+ np_adv::V1DeserializedSection<
+ 'adv,
+ np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>,
+ >,
+ >,
) -> Result<Self, Self::Error> {
let sections = contents
.into_iter()
@@ -142,8 +160,12 @@
impl LocksLongerThan<LegibleV1Sections> for CredentialBook {}
impl LegibleV1Sections {
- pub(crate) fn allocate_with_contents<M: np_adv::credential::MatchedCredential>(
- contents: Vec<np_adv::V1DeserializedSection<M>>,
+ pub(crate) fn allocate_with_contents(
+ contents: Vec<
+ np_adv::V1DeserializedSection<
+ np_adv::credential::ReferencedMatchedCredential<MatchedCredential>,
+ >,
+ >,
) -> Result<Self, DeserializeAdvertisementError> {
let section = LegibleV1SectionsInternals::try_from(contents)
.map_err(|_| DeserializeAdvertisementError)?;
@@ -190,10 +212,45 @@
declare_enum_cast! {into_success, Success, DeserializedV1Section}
}
+/// Discriminant for `GetV1DE16ByteSaltResult`.
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum GetV1DE16ByteSaltResultKind {
+ /// The attempt to get the derived salt failed, possibly
+ /// because the passed DE offset was invalid (==255),
+ /// or because there was no salt included for the
+ /// referenced advertisement section (i.e: it was
+ /// a public advertisement section, or it was deallocated.)
+ Error = 0,
+ /// A 16-byte salt for the given DE offset was successfully
+ /// derived.
+ Success = 1,
+}
+
+/// The result of attempting to get a derived 16-byte salt
+/// for a given DE within a section.
+#[derive(Copy, Clone)]
+#[repr(C)]
+#[allow(missing_docs)]
+pub enum GetV1DE16ByteSaltResult {
+ Error,
+ Success([u8; 16]),
+}
+
+impl FfiEnum for GetV1DE16ByteSaltResult {
+ type Kind = GetV1DE16ByteSaltResultKind;
+ fn kind(&self) -> Self::Kind {
+ match self {
+ GetV1DE16ByteSaltResult::Error => GetV1DE16ByteSaltResultKind::Error,
+ GetV1DE16ByteSaltResult::Success(_) => GetV1DE16ByteSaltResultKind::Success,
+ }
+ }
+}
+
/// The internal FFI-friendly representation of a deserialized v1 section
pub struct DeserializedV1SectionInternals {
des: Vec<V1DataElement>,
- identity: DeserializedV1Identity,
+ identity: Option<DeserializedV1IdentityInternals>,
}
impl DeserializedV1SectionInternals {
@@ -203,7 +260,11 @@
}
/// Gets the enum tag of the identity used for this section.
fn identity_kind(&self) -> DeserializedV1IdentityKind {
- self.identity.kind()
+ if self.identity.is_some() {
+ DeserializedV1IdentityKind::Decrypted
+ } else {
+ DeserializedV1IdentityKind::Plaintext
+ }
}
/// Attempts to get the DE with the given index in this section.
fn get_de(&self, index: u8) -> GetV1DEResult {
@@ -212,14 +273,53 @@
None => GetV1DEResult::Error,
}
}
+ /// Attempts to get the directly-transmissible details about
+ /// the deserialized V1 identity for this section. Does
+ /// not include decrypted metadata bytes nor the section salt.
+ pub(crate) fn get_identity_details(&self) -> GetV1IdentityDetailsResult {
+ match &self.identity {
+ Some(identity) => GetV1IdentityDetailsResult::Success(identity.details()),
+ None => GetV1IdentityDetailsResult::Error,
+ }
+ }
+ /// Attempts to decrypt the metadata for the matched
+ /// credential for this V1 section (if any).
+ pub(crate) fn decrypt_metadata(&self) -> Result<Vec<u8>, DecryptMetadataError> {
+ match &self.identity {
+ None => Err(DecryptMetadataError::EncryptedMetadataNotAvailable),
+ Some(identity) => {
+ identity.decrypt_metadata().ok_or(DecryptMetadataError::DecryptionFailed)
+ }
+ }
+ }
+ /// Attempts to derive a 16-byte DE salt for a DE in this section
+ /// with the given DE offset. This operation may fail if the
+ /// passed offset is 255 (causes overflow) or if the section
+ /// is leveraging a public identity, and hence, doesn't have
+ /// an associated salt.
+ pub(crate) fn derive_16_byte_salt_for_offset(&self, de_offset: u8) -> GetV1DE16ByteSaltResult {
+ self.identity
+ .as_ref()
+ .and_then(|x| x.derive_16_byte_salt_for_offset(de_offset))
+ .map_or(GetV1DE16ByteSaltResult::Error, GetV1DE16ByteSaltResult::Success)
+ }
}
-impl<'adv, M: np_adv::credential::MatchedCredential> TryFrom<np_adv::V1DeserializedSection<'adv, M>>
- for DeserializedV1SectionInternals
+impl<'adv>
+ TryFrom<
+ np_adv::V1DeserializedSection<
+ 'adv,
+ np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>,
+ >,
+ > for DeserializedV1SectionInternals
{
type Error = DataElementParseError;
- fn try_from(section: np_adv::V1DeserializedSection<M>) -> Result<Self, Self::Error> {
+ fn try_from(
+ section: np_adv::V1DeserializedSection<
+ np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>,
+ >,
+ ) -> Result<Self, Self::Error> {
use np_adv::extended::deserialize::Section;
use np_adv::V1DeserializedSection;
match section {
@@ -228,11 +328,30 @@
.iter_data_elements()
.map(|r| r.map(|de| V1DataElement::from(&de)))
.collect::<Result<Vec<_>, _>>()?;
- let identity = DeserializedV1Identity::Plaintext;
+ let identity = None;
Ok(Self { des, identity })
}
- V1DeserializedSection::Decrypted(_) => {
- unimplemented!();
+ V1DeserializedSection::Decrypted(with_matched) => {
+ let section = with_matched.contents();
+ let des = section
+ .iter_data_elements()
+ .map(|r| r.map(|de| V1DataElement::from(&de)))
+ .collect::<Result<Vec<_>, _>>()?;
+
+ let identity_type = section.identity_type();
+ let verification_mode = section.verification_mode();
+ let salt = section.salt();
+
+ let match_data = with_matched.clone_match_data();
+ let match_data = match_data.map(|x| x.metadata_key());
+
+ let identity = Some(DeserializedV1IdentityInternals::new(
+ identity_type,
+ verification_mode,
+ salt,
+ match_data,
+ ));
+ Ok(Self { des, identity })
}
}
}
@@ -248,27 +367,168 @@
Decrypted = 1,
}
-/// Deserialized information about the identity
-/// employed in a V1 adveritsement section.
-#[derive(Clone, Copy)]
-#[repr(C)]
-#[allow(missing_docs)]
-pub enum DeserializedV1Identity {
- Plaintext,
- // TODO: This gets a payload once we support creds
- Decrypted,
+/// Internals for the representation of a decrypted
+/// V1 section identity.
+pub(crate) struct DeserializedV1IdentityInternals {
+ /// The details about the identity, suitable
+ /// for direct communication over FFI
+ details: DeserializedV1IdentityDetails,
+ /// The metadata key, together with the matched
+ /// credential and enough information to decrypt
+ /// the credential metadata, if desired.
+ match_data: np_adv::WithMatchedCredential<MatchedCredential, np_adv::MetadataKey>,
+ /// The 16-byte section salt
+ salt: np_adv::extended::deserialize::RawV1Salt,
}
-impl FfiEnum for DeserializedV1Identity {
- type Kind = DeserializedV1IdentityKind;
+impl DeserializedV1IdentityInternals {
+ pub(crate) fn new(
+ identity_type: np_adv::de_type::EncryptedIdentityDataElementType,
+ verification_mode: np_adv::extended::deserialize::VerificationMode,
+ salt: np_adv::extended::deserialize::RawV1Salt,
+ match_data: np_adv::WithMatchedCredential<MatchedCredential, np_adv::MetadataKey>,
+ ) -> Self {
+ let cred_id = match_data.matched_credential().id();
+ let metadata_key = match_data.contents();
+ let details = DeserializedV1IdentityDetails::new(
+ cred_id,
+ identity_type,
+ verification_mode,
+ *metadata_key,
+ );
+ Self { details, match_data, salt }
+ }
+ /// Gets the directly-transmissible details about
+ /// this deserialized V1 identity. Does not include
+ /// decrypted metadata bytes nor the section salt.
+ pub(crate) fn details(&self) -> DeserializedV1IdentityDetails {
+ self.details
+ }
+ /// Attempts to decrypt the metadata associated
+ /// with this identity.
+ pub(crate) fn decrypt_metadata(&self) -> Option<Vec<u8>> {
+ self.match_data.decrypt_metadata::<CryptoProviderImpl>().ok()
+ }
+ /// For a given data-element offset, derives a 16-byte DE salt
+ /// for a DE in that position within this section.
+ pub(crate) fn derive_16_byte_salt_for_offset(&self, de_offset: u8) -> Option<[u8; 16]> {
+ let section_salt = np_hkdf::v1_salt::V1Salt::<CryptoProviderImpl>::from(self.salt);
+ let de_offset = np_hkdf::v1_salt::DataElementOffset::from(de_offset);
+ section_salt.derive::<16>(Some(de_offset))
+ }
+}
+
+/// Information about the verification scheme used
+/// for verifying the integrity of the contents
+/// of a decrypted section.
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum V1VerificationMode {
+ /// Message integrity code verification.
+ Mic = 0,
+ /// Signature verification.
+ Signature = 1,
+}
+
+impl From<np_adv::extended::deserialize::VerificationMode> for V1VerificationMode {
+ fn from(verification_mode: np_adv::extended::deserialize::VerificationMode) -> Self {
+ use np_adv::extended::deserialize::VerificationMode;
+ match verification_mode {
+ VerificationMode::Mic => Self::Mic,
+ VerificationMode::Signature => Self::Signature,
+ }
+ }
+}
+
+/// Discriminant for `GetV1IdentityDetailsResult`
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum GetV1IdentityDetailsResultKind {
+ /// The attempt to get the identity details
+ /// for the section failed, possibly
+ /// due to the section being a public
+ /// section, or the underlying
+ /// advertisement has already been deallocated.
+ Error = 0,
+ /// The attempt to get the identity details succeeded.
+ /// The wrapped identity details may be obtained via
+ /// `GetV1IdentityDetailsResult#into_success`.
+ Success = 1,
+}
+
+/// The result of attempting to get the identity details
+/// for a V1 advertisement section via
+/// `DeserializedV1Advertisement#get_identity_details`.
+#[repr(C)]
+#[allow(missing_docs)]
+pub enum GetV1IdentityDetailsResult {
+ Error,
+ Success(DeserializedV1IdentityDetails),
+}
+
+impl FfiEnum for GetV1IdentityDetailsResult {
+ type Kind = GetV1IdentityDetailsResultKind;
fn kind(&self) -> Self::Kind {
match self {
- DeserializedV1Identity::Plaintext => DeserializedV1IdentityKind::Plaintext,
- DeserializedV1Identity::Decrypted => DeserializedV1IdentityKind::Decrypted,
+ GetV1IdentityDetailsResult::Error => GetV1IdentityDetailsResultKind::Error,
+ GetV1IdentityDetailsResult::Success(_) => GetV1IdentityDetailsResultKind::Success,
}
}
}
+impl GetV1IdentityDetailsResult {
+ declare_enum_cast! {into_success, Success, DeserializedV1IdentityDetails}
+}
+
+/// Information about the identity which matched
+/// a decrypted V1 section.
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct DeserializedV1IdentityDetails {
+ /// The identity type (private/provisioned/trusted)
+ identity_type: EncryptedIdentityType,
+ /// The verification mode (MIC/Signature) which
+ /// was used to verify the decrypted adv contents.
+ verification_mode: V1VerificationMode,
+ /// The ID of the credential which
+ /// matched the deserialized section.
+ cred_id: u32,
+ /// The 16-byte metadata key.
+ metadata_key: [u8; 16],
+}
+
+impl DeserializedV1IdentityDetails {
+ pub(crate) fn new(
+ cred_id: u32,
+ identity_type: np_adv::de_type::EncryptedIdentityDataElementType,
+ verification_mode: np_adv::extended::deserialize::VerificationMode,
+ metadata_key: np_adv::MetadataKey,
+ ) -> Self {
+ let metadata_key = metadata_key.0;
+ let identity_type = identity_type.into();
+ let verification_mode = verification_mode.into();
+ Self { cred_id, identity_type, verification_mode, metadata_key }
+ }
+ /// Returns the ID of the credential which
+ /// matched the deserialized section.
+ pub fn cred_id(&self) -> u32 {
+ self.cred_id
+ }
+ /// Returns the identity type (private/provisioned/trusted)
+ pub fn identity_type(&self) -> EncryptedIdentityType {
+ self.identity_type
+ }
+ /// Returns the verification mode (MIC/Signature)
+ /// employed for the decrypted section.
+ pub fn verification_mode(&self) -> V1VerificationMode {
+ self.verification_mode
+ }
+ /// Returns the 16-byte section metadata key.
+ pub fn metadata_key(&self) -> [u8; 16] {
+ self.metadata_key
+ }
+}
+
/// Handle to a deserialized V1 section
#[repr(C)]
pub struct DeserializedV1Section {
@@ -290,20 +550,60 @@
self.identity_tag
}
- /// Gets the DE with the given index in this section.
- pub fn get_de(&self, de_index: u8) -> GetV1DEResult {
+ fn apply_to_section_internals<R>(
+ &self,
+ func: impl FnOnce(&DeserializedV1SectionInternals) -> R,
+ lookup_failure_result: R,
+ ) -> R {
// TODO: Once the `FromResidual` trait is stabilized, this can be simplified.
match self.legible_sections_handle.get() {
Ok(legible_sections_read_guard) => {
match legible_sections_read_guard.get_section_internals(self.legible_section_index)
{
- Some(section_ref) => section_ref.get_de(de_index),
- None => GetV1DEResult::Error,
+ Some(section_ref) => func(section_ref),
+ None => lookup_failure_result,
}
}
- Err(_) => GetV1DEResult::Error,
+ Err(_) => lookup_failure_result,
}
}
+ /// Gets the DE with the given index in this section.
+ pub fn get_de(&self, de_index: u8) -> GetV1DEResult {
+ self.apply_to_section_internals(
+ move |section_ref| section_ref.get_de(de_index),
+ GetV1DEResult::Error,
+ )
+ }
+ /// Attempts to get the details of the identity employed
+ /// for the section referenced by this handle. May fail
+ /// if the handle is invalid, or if the advertisement
+ /// section leverages a public identity.
+ pub fn get_identity_details(&self) -> GetV1IdentityDetailsResult {
+ self.apply_to_section_internals(
+ DeserializedV1SectionInternals::get_identity_details,
+ GetV1IdentityDetailsResult::Error,
+ )
+ }
+ /// Attempts to decrypt the metadata for the matched
+ /// credential for the V1 section referenced by
+ /// this handle (if any).
+ pub fn decrypt_metadata(&self) -> Result<Vec<u8>, DecryptMetadataError> {
+ self.apply_to_section_internals(
+ DeserializedV1SectionInternals::decrypt_metadata,
+ Err(DecryptMetadataError::EncryptedMetadataNotAvailable),
+ )
+ }
+ /// Attempts to derive a 16-byte DE salt for a DE in this section
+ /// with the given DE offset. This operation may fail if the
+ /// passed offset is 255 (causes overflow) or if the section
+ /// is leveraging a public identity, and hence, doesn't have
+ /// an associated salt.
+ pub fn derive_16_byte_salt_for_offset(&self, de_offset: u8) -> GetV1DE16ByteSaltResult {
+ self.apply_to_section_internals(
+ move |section_ref| section_ref.derive_16_byte_salt_for_offset(de_offset),
+ GetV1DE16ByteSaltResult::Error,
+ )
+ }
}
/// Discriminant for the `GetV1DEResult` enum.
@@ -365,13 +665,14 @@
impl<'a> From<&'a np_adv::extended::deserialize::DataElement<'a>> for V1DataElement {
fn from(de: &'a np_adv::extended::deserialize::DataElement<'a>) -> Self {
+ let offset = de.offset().as_u8();
let de_type = V1DEType::from(de.de_type());
let contents_as_slice = de.contents();
//Guaranteed not to panic due DE size limit.
#[allow(clippy::unwrap_used)]
let array_view: ArrayView<u8, 127> = ArrayView::try_from_slice(contents_as_slice).unwrap();
let payload = ByteBuffer::from_array_view(array_view);
- Self::Generic(GenericV1DataElement { de_type, payload })
+ Self::Generic(GenericV1DataElement { de_type, offset, payload })
}
}
@@ -381,6 +682,8 @@
#[derive(Clone)]
#[repr(C)]
pub struct GenericV1DataElement {
+ /// The offset of this generic data-element.
+ pub offset: u8,
/// The DE type code of this generic data-element.
pub de_type: V1DEType,
/// The raw data-element byte payload, up to
@@ -389,6 +692,10 @@
}
impl GenericV1DataElement {
+ /// Gets the offset for this generic V1 data element.
+ pub fn offset(&self) -> u8 {
+ self.offset
+ }
/// Gets the DE-type of this generic V1 data element.
pub fn de_type(&self) -> V1DEType {
self.de_type
diff --git a/nearby/presence/np_ffi_core/src/lib.rs b/nearby/presence/np_ffi_core/src/lib.rs
index bba33e2..0c25168 100644
--- a/nearby/presence/np_ffi_core/src/lib.rs
+++ b/nearby/presence/np_ffi_core/src/lib.rs
@@ -11,15 +11,8 @@
// 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.
+
//! Core functionality common to all NP Rust FFI layers
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::indexing_slicing,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used
-)]
#[macro_use]
extern crate lazy_static;
diff --git a/nearby/presence/np_hkdf/Cargo.toml b/nearby/presence/np_hkdf/Cargo.toml
index 885913f..45e40da 100644
--- a/nearby/presence/np_hkdf/Cargo.toml
+++ b/nearby/presence/np_hkdf/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
std = []
diff --git a/nearby/presence/np_hkdf/benches/np_hkdf.rs b/nearby/presence/np_hkdf/benches/np_hkdf.rs
index e3ce506..bec3b0e 100644
--- a/nearby/presence/np_hkdf/benches/np_hkdf.rs
+++ b/nearby/presence/np_hkdf/benches/np_hkdf.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(missing_docs, unused_results)]
+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use crypto_provider::{CryptoProvider, CryptoRng};
use crypto_provider_default::CryptoProviderImpl;
diff --git a/nearby/presence/np_hkdf/src/lib.rs b/nearby/presence/np_hkdf/src/lib.rs
index f4f98eb..8201f38 100644
--- a/nearby/presence/np_hkdf/src/lib.rs
+++ b/nearby/presence/np_hkdf/src/lib.rs
@@ -16,17 +16,9 @@
//!
//! All HKDF calls should happen in this module and expose the correct result type for
//! each derived key use case.
-#![no_std]
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::indexing_slicing,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used
-)]
-extern crate core;
+#![no_std]
+
#[cfg(feature = "std")]
extern crate std;
diff --git a/nearby/presence/np_hkdf/src/v1_salt.rs b/nearby/presence/np_hkdf/src/v1_salt.rs
index ae327db..94e6855 100644
--- a/nearby/presence/np_hkdf/src/v1_salt.rs
+++ b/nearby/presence/np_hkdf/src/v1_salt.rs
@@ -45,7 +45,7 @@
&[
b"V1 derived salt",
&de.and_then(|d| d.offset.checked_add(1))
- .and_then(|o| o.try_into().ok())
+ .map(|o| o.into())
.unwrap_or(0_u32)
.to_be_bytes(),
],
diff --git a/nearby/presence/np_hkdf/tests/test_vectors.rs b/nearby/presence/np_hkdf/tests/test_vectors.rs
index 380c107..175e73e 100644
--- a/nearby/presence/np_hkdf/tests/test_vectors.rs
+++ b/nearby/presence/np_hkdf/tests/test_vectors.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::indexing_slicing, clippy::unwrap_used)]
+
use anyhow::anyhow;
use crypto_provider::aes::AesKey;
use crypto_provider_default::CryptoProviderImpl;
@@ -28,7 +30,7 @@
test_helper::get_data_file("presence/np_hkdf/resources/test/hkdf-test-vectors.json");
let mut file = fs::File::open(full_path)?;
let mut data = String::new();
- file.read_to_string(&mut data)?;
+ let _ = file.read_to_string(&mut data)?;
let test_cases = match serde_json::de::from_str(&data)? {
serde_json::Value::Array(a) => a,
_ => return Err(anyhow!("bad json")),
diff --git a/nearby/presence/rand_ext/Cargo.toml b/nearby/presence/rand_ext/Cargo.toml
index bbdb5af..79a8ea8 100644
--- a/nearby/presence/rand_ext/Cargo.toml
+++ b/nearby/presence/rand_ext/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
crypto_provider.workspace = true
log.workspace = true
diff --git a/nearby/presence/rand_ext/src/lib.rs b/nearby/presence/rand_ext/src/lib.rs
index 9819c6b..d767143 100644
--- a/nearby/presence/rand_ext/src/lib.rs
+++ b/nearby/presence/rand_ext/src/lib.rs
@@ -14,8 +14,6 @@
//! Helper functions around `rand`'s offerings for convenient test usage.
#![no_std]
-#![forbid(unsafe_code)]
-#![deny(missing_docs)]
extern crate alloc;
diff --git a/nearby/presence/sink/Cargo.toml b/nearby/presence/sink/Cargo.toml
index a0322b6..a479205 100644
--- a/nearby/presence/sink/Cargo.toml
+++ b/nearby/presence/sink/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
tinyvec.workspace = true
diff --git a/nearby/presence/sink/src/lib.rs b/nearby/presence/sink/src/lib.rs
index 75c7c1d..fe6e5b6 100644
--- a/nearby/presence/sink/src/lib.rs
+++ b/nearby/presence/sink/src/lib.rs
@@ -14,15 +14,8 @@
//! A no_std-friendly data-writing "sink" trait which allows for convenient expression
//! of "write me into a limited-size buffer"-type methods on traits.
+
#![cfg_attr(not(feature = "std"), no_std)]
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::indexing_slicing,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used
-)]
/// An append-only, limited-size collection.
pub trait Sink<T> {
diff --git a/nearby/presence/test_helper/Cargo.toml b/nearby/presence/test_helper/Cargo.toml
index 488ea74..c52d6bf 100644
--- a/nearby/presence/test_helper/Cargo.toml
+++ b/nearby/presence/test_helper/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
hex.workspace = true
serde_json.workspace = true
diff --git a/nearby/presence/test_helper/src/lib.rs b/nearby/presence/test_helper/src/lib.rs
index 7c0694f..8b42623 100644
--- a/nearby/presence/test_helper/src/lib.rs
+++ b/nearby/presence/test_helper/src/lib.rs
@@ -11,11 +11,11 @@
// 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.
-#![forbid(unsafe_code)]
-#![deny(missing_docs)]
//! Helper crate for common functions used in testing
+#![allow(clippy::unwrap_used, clippy::expect_used)]
+
use std::fs;
use std::io::Read;
@@ -33,7 +33,7 @@
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");
+ let _ = file.read_to_string(&mut data).expect("should be able to read data file");
data
}
@@ -45,12 +45,12 @@
/// extract a string from a jsonvalue
pub fn extract_key_str<'a>(value: &'a serde_json::Value, key: &str) -> &'a str {
- value[key].as_str().unwrap()
+ value.get(key).unwrap().as_str().unwrap()
}
/// Decode a hex-encoded vec at `key`
pub fn extract_key_vec(value: &serde_json::Value, key: &str) -> Vec<u8> {
- hex::decode(value[key].as_str().unwrap()).unwrap()
+ hex::decode(value.get(key).unwrap().as_str().unwrap()).unwrap()
}
/// Decode a hex-encoded array at `key`
diff --git a/nearby/presence/xts_aes/Cargo.toml b/nearby/presence/xts_aes/Cargo.toml
index ba7aadb..86745c4 100644
--- a/nearby/presence/xts_aes/Cargo.toml
+++ b/nearby/presence/xts_aes/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[features]
default = []
std = []
@@ -14,7 +17,7 @@
ldt_tbc.workspace = true
[dev-dependencies]
-crypto_provider_default = {workspace = true, features = ["rustcrypto"]}
+crypto_provider_default = { workspace = true, features = ["rustcrypto"] }
rand_ext.workspace = true
test_helper.workspace = true
wycheproof.workspace = true
diff --git a/nearby/presence/xts_aes/src/lib.rs b/nearby/presence/xts_aes/src/lib.rs
index ac2cf15..e8a80a1 100644
--- a/nearby/presence/xts_aes/src/lib.rs
+++ b/nearby/presence/xts_aes/src/lib.rs
@@ -12,21 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#![no_std]
-#![forbid(unsafe_code)]
-#![deny(
- missing_docs,
- clippy::unwrap_used,
- clippy::panic,
- clippy::expect_used,
- clippy::indexing_slicing
-)]
-
//! Implementation of the XTS-AES tweakable block cipher.
//!
//! See NIST docs [here](https://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/1619-2007-NIST-Submission.pdf)
//! and [here](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38e.pdf).
+#![no_std]
+
#[cfg(feature = "std")]
extern crate std;
diff --git a/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs b/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs
index 94ed066..abe1077 100644
--- a/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs
+++ b/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use aes::{cipher, cipher::KeyInit as _};
use alloc::vec::Vec;
use crypto_provider::aes::*;
diff --git a/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs b/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs
index 724e3bd..1f92f89 100644
--- a/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs
+++ b/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-extern crate core;
+#![allow(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing)]
use crypto_provider::CryptoProvider;
use crypto_provider_default::CryptoProviderImpl;
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 3d0cb50..6ceb8b9 100644
--- a/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs
+++ b/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-extern crate core;
+#![allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
use anyhow::anyhow;
use crypto_provider::CryptoProvider;
@@ -225,7 +225,7 @@
// `key = value` in a test case chunk
if let Some(captures) = regex::Regex::new("^(.*) = (.*)$").unwrap().captures(&line) {
- map.insert(
+ let _ = map.insert(
captures.get(1).unwrap().as_str().to_owned(),
captures.get(2).unwrap().as_str().to_owned(),
);
diff --git a/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs b/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs
index 0e28dfa..924b665 100644
--- a/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs
+++ b/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#![allow(clippy::unwrap_used)]
+
use alloc::vec::Vec;
use crypto_provider::aes::*;
use crypto_provider::CryptoProvider;
diff --git a/nearby/src/main.rs b/nearby/src/main.rs
index eaf3ed2..3d698e2 100644
--- a/nearby/src/main.rs
+++ b/nearby/src/main.rs
@@ -38,6 +38,7 @@
Subcommand::CheckEverything { ref check_options } => {
check_everything(&root_dir, check_options)?
}
+ Subcommand::CleanEverything => clean_everything(&root_dir)?,
Subcommand::CheckWorkspace(ref options) => check_workspace(&root_dir, options)?,
Subcommand::FfiCheckEverything(ref options) => ffi::check_everything(&root_dir, options)?,
Subcommand::BoringsslCheckEverything(ref options) => {
@@ -95,6 +96,8 @@
Ok(())
}
+
+/// Runs checks to ensure lints are passing and all targets are building
pub fn check_everything(root: &path::Path, check_options: &CheckOptions) -> anyhow::Result<()> {
license::check_license_headers(root)?;
check_workspace(root, check_options)?;
@@ -110,6 +113,15 @@
Ok(())
}
+pub fn clean_everything(root: &path::Path) -> anyhow::Result<()> {
+ run_cmd_shell(root, "cargo clean")?;
+ run_cmd_shell(&root.join("presence/ldt_np_adv_ffi"), "cargo clean")?;
+ run_cmd_shell(&root.join("presence/np_c_ffi"), "cargo clean")?;
+ run_cmd_shell(&root.join("crypto/crypto_provider_boringssl"), "cargo clean")?;
+ run_cmd_shell(&root.join("connections/ukey2/ukey2_c_ffi"), "cargo clean")?;
+ Ok(())
+}
+
#[derive(clap::Parser)]
struct Cli {
#[clap(subcommand)]
@@ -123,6 +135,9 @@
#[command(flatten)]
check_options: CheckOptions,
},
+ /// Cleans the main workspace and all sub projects - useful if upgrading rust compiler version
+ /// and need dependencies to be compiled with the same version
+ CleanEverything,
/// Checks everything included in the top level workspace
CheckWorkspace(CheckOptions),
/// Checks everything related to the boringssl version (equivalent of running check-boringssl
diff --git a/nearby/util/handle_map/Cargo.toml b/nearby/util/handle_map/Cargo.toml
index fbe3a20..13973d4 100644
--- a/nearby/util/handle_map/Cargo.toml
+++ b/nearby/util/handle_map/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
lock_adapter.workspace = true
diff --git a/nearby/util/handle_map/benches/benches.rs b/nearby/util/handle_map/benches/benches.rs
index f1ee427..f1988ba 100644
--- a/nearby/util/handle_map/benches/benches.rs
+++ b/nearby/util/handle_map/benches/benches.rs
@@ -11,6 +11,9 @@
// 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.
+
+#![allow(missing_docs, unused_results, clippy::unwrap_used)]
+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use handle_map::*;
use std::sync::Arc;
@@ -45,7 +48,7 @@
let handle = handle_map.allocate(|| 0xFF).unwrap();
let handle_map_ref = &handle_map;
// Perform repeated reads
- c.bench_function("single-threaded reads", |b| {
+ let _ = c.bench_function("single-threaded reads", |b| {
b.iter(|| {
let guard = handle_map_ref.get(black_box(handle)).unwrap();
black_box(*guard)
diff --git a/nearby/util/handle_map/src/declare_handle_map.rs b/nearby/util/handle_map/src/declare_handle_map.rs
index dbdc77f..c19a012 100644
--- a/nearby/util/handle_map/src/declare_handle_map.rs
+++ b/nearby/util/handle_map/src/declare_handle_map.rs
@@ -131,6 +131,13 @@
}
impl $crate::HandleLike for $handle_type_name {
type Object = $wrapped_type;
+ fn try_allocate<E: core::fmt::Debug>(
+ initial_value_provider: impl FnOnce() -> Result<$wrapped_type, E>,
+ ) -> Result<Self, $crate::HandleMapTryAllocateError<E>> {
+ GLOBAL_HANDLE_MAP
+ .try_allocate(initial_value_provider)
+ .map(|derived_handle| Self { handle_id: derived_handle.get_id() })
+ }
fn allocate(
initial_value_provider: impl FnOnce() -> $wrapped_type,
) -> Result<Self, $crate::HandleMapFullError> {
diff --git a/nearby/util/handle_map/src/guard.rs b/nearby/util/handle_map/src/guard.rs
index 4a96bb5..0c8c9d7 100644
--- a/nearby/util/handle_map/src/guard.rs
+++ b/nearby/util/handle_map/src/guard.rs
@@ -60,17 +60,13 @@
type Ret = T;
fn map<'b>(&self, arg: &'b Self::Arg) -> &'b Self::Ret {
- // We know that the entry exists, since we've locked the
- // shard and already checked that it exists prior to
- // handing out this new, mapped read-lock.
- arg.get(&self.handle).unwrap()
+ #[allow(clippy::expect_used)]
+ arg.get(&self.handle).expect("We know that the entry exists, since we've locked the shard and already checked that it exists prior to handing out this new, mapped read-lock.")
}
fn map_mut<'b>(&self, arg: &'b mut Self::Arg) -> &'b mut Self::Ret {
- // We know that the entry exists, since we've locked the
- // shard and already checked that it exists prior to
- // handing out this new, mapped read-lock.
- arg.get_mut(&self.handle).unwrap()
+ #[allow(clippy::expect_used)]
+ arg.get_mut(&self.handle).expect("We know that the entry exists, since we've locked the shard and already checked that it exists prior to handing out this new, mapped read-lock.")
}
}
@@ -134,10 +130,12 @@
type Ret = T;
fn map<'b>(&self, arg: &'b Self::Arg) -> &'b Self::Ret {
- arg.get(&self.handle).unwrap()
+ #[allow(clippy::expect_used)]
+ arg.get(&self.handle).expect("Caller must verify that provided hande exists")
}
fn map_mut<'b>(&self, arg: &'b mut Self::Arg) -> &'b mut Self::Ret {
- arg.get_mut(&self.handle).unwrap()
+ #[allow(clippy::expect_used)]
+ arg.get_mut(&self.handle).expect("Caller must verify that provided hande exists")
}
}
diff --git a/nearby/util/handle_map/src/lib.rs b/nearby/util/handle_map/src/lib.rs
index bb420e3..22009c1 100644
--- a/nearby/util/handle_map/src/lib.rs
+++ b/nearby/util/handle_map/src/lib.rs
@@ -15,9 +15,7 @@
//! A thread-safe implementation of a map for managing object handles,
//! a safer alternative to raw pointers for FFI interop.
-#![forbid(unsafe_code)]
-#![deny(missing_docs)]
-
+use core::fmt::Debug;
use std::boxed::Box;
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use std::vec::Vec;
@@ -84,6 +82,17 @@
#[derive(Debug)]
pub struct HandleNotPresentError;
+/// Errors which may be raised while attempting to allocate
+/// a handle from contents given by a (fallible) value-provider.
+#[derive(Debug)]
+pub enum HandleMapTryAllocateError<E: Debug> {
+ /// The call to the value-provider for the allocation failed.
+ ValueProviderFailed(E),
+ /// We couldn't reserve a spot for the allocation, because
+ /// the handle-map was full.
+ HandleMapFull,
+}
+
/// FFI-transmissible structure expressing the dimensions
/// (max # of allocatable slots, number of shards) of a handle-map
/// to be used upon initialization.
@@ -142,10 +151,35 @@
/// may fail if attempting to allocate over the `dimensions.max_active_handles`
/// limit imposed on the handle-map, in which case this method
/// will return a `HandleMapFullError`.
+ ///
+ /// If you want the passed closure to be able to possibly fail, see
+ /// [`Self::try_allocate`] instead.
pub fn allocate(
&self,
initial_value_provider: impl FnOnce() -> T,
) -> Result<Handle, HandleMapFullError> {
+ let wrapped_value_provider = move || Ok(initial_value_provider());
+ self.try_allocate::<core::convert::Infallible>(wrapped_value_provider).map_err(
+ |e| match e {
+ HandleMapTryAllocateError::ValueProviderFailed(never) => match never {},
+ HandleMapTryAllocateError::HandleMapFull => HandleMapFullError,
+ },
+ )
+ }
+
+ /// Attempts to allocate a new object within the given handle-map, returning
+ /// a handle to the location it was stored at. This operation
+ /// may fail if attempting to allocate over the `dimensions.max_active_handles`
+ /// limit imposed on the handle-map, in which case this method
+ /// will return a `HandleMapTryAllocateError::HandleMapFull`,
+ /// or if the passed initial-value provider fails, in which case this
+ /// will return the error wrapped in `HandleMapTryAllocateError::ValueProviderFailed`.
+ ///
+ /// If your initial-value provider is infallible, see [`Self::allocate`] instead.
+ pub fn try_allocate<E: Debug>(
+ &self,
+ initial_value_provider: impl FnOnce() -> Result<T, E>,
+ ) -> Result<Handle, HandleMapTryAllocateError<E>> {
let mut initial_value_provider = initial_value_provider;
loop {
// Increment the new-handle-ID counter using relaxed memory ordering,
@@ -156,18 +190,26 @@
let shard_index = new_handle.get_shard_index(self.dimensions.num_shards);
// Now, check the shard to see if we can actually allocate into it.
- let shard_allocate_result = self.handle_map_shards[shard_index].try_allocate(
- new_handle,
- initial_value_provider,
- &self.outstanding_allocations_counter,
- self.dimensions.max_active_handles,
- );
+ #[allow(clippy::expect_used)]
+ let shard_allocate_result = self
+ .handle_map_shards
+ .get(shard_index)
+ .expect("Shard index is always within range")
+ .try_allocate(
+ new_handle,
+ initial_value_provider,
+ &self.outstanding_allocations_counter,
+ self.dimensions.max_active_handles,
+ );
match shard_allocate_result {
Ok(_) => {
return Ok(new_handle);
}
+ Err(ShardAllocationError::ValueProviderFailed(e)) => {
+ return Err(HandleMapTryAllocateError::ValueProviderFailed(e))
+ }
Err(ShardAllocationError::ExceedsAllocationLimit) => {
- return Err(HandleMapFullError);
+ return Err(HandleMapTryAllocateError::HandleMapFull);
}
Err(ShardAllocationError::EntryOccupied(thrown_back_provider)) => {
// We need to do the whole thing again with a new ID
@@ -181,7 +223,11 @@
/// if the given handle is present. Otherwise, returns [`HandleNotPresentError`].
pub fn get(&self, handle: Handle) -> Result<ObjectReadGuardImpl<T>, HandleNotPresentError> {
let shard_index = handle.get_shard_index(self.dimensions.num_shards);
- self.handle_map_shards[shard_index].get(handle)
+ #[allow(clippy::expect_used)]
+ self.handle_map_shards
+ .get(shard_index)
+ .expect("shard index is always within range")
+ .get(handle)
}
/// Gets a read+write reference to an object within the given handle-map,
@@ -191,7 +237,11 @@
handle: Handle,
) -> Result<ObjectReadWriteGuardImpl<T>, HandleNotPresentError> {
let shard_index = handle.get_shard_index(self.dimensions.num_shards);
- self.handle_map_shards[shard_index].get_mut(handle)
+ #[allow(clippy::expect_used)]
+ self.handle_map_shards
+ .get(shard_index)
+ .expect("shard_index is always in range")
+ .get_mut(handle)
}
/// Removes the object pointed to by the given handle in
@@ -199,7 +249,10 @@
/// exists. Otherwise, returns [`HandleNotPresentError`].
pub fn deallocate(&self, handle: Handle) -> Result<T, HandleNotPresentError> {
let shard_index = handle.get_shard_index(self.dimensions.num_shards);
- self.handle_map_shards[shard_index]
+ #[allow(clippy::expect_used)]
+ self.handle_map_shards
+ .get(shard_index)
+ .expect("shard index is always in range")
.deallocate(handle, &self.outstanding_allocations_counter)
}
@@ -224,9 +277,16 @@
/// The underlying object type pointed-to by this handle
type Object: Send + Sync;
- /// Tries to allocate a new handle using the given provider
- /// to construct the underlying stored object as a new
- /// entry into the global handle table for this type.
+ /// Tries to allocate a new handle using the given (fallible)
+ /// provider to construct the underlying stored object as
+ /// a new entry into the global handle table for this type.
+ fn try_allocate<E: Debug>(
+ initial_value_provider: impl FnOnce() -> Result<Self::Object, E>,
+ ) -> Result<Self, HandleMapTryAllocateError<E>>;
+
+ /// Tries to allocate a new handle using the given (infallible)
+ /// provider to construct the underlying stored object as
+ /// a new entry into the global handle table for this type.
fn allocate(
initial_value_provider: impl FnOnce() -> Self::Object,
) -> Result<Self, HandleMapFullError>;
diff --git a/nearby/util/handle_map/src/shard.rs b/nearby/util/handle_map/src/shard.rs
index da3bd57..e5aad2f 100644
--- a/nearby/util/handle_map/src/shard.rs
+++ b/nearby/util/handle_map/src/shard.rs
@@ -33,13 +33,15 @@
type ShardReadWriteGuard<'a, T> = RwLockWriteGuard<'a, ShardMapType<T>>;
/// Internal error enum for failed allocations into a given shard.
-pub(crate) enum ShardAllocationError<T, F: FnOnce() -> T> {
+pub(crate) enum ShardAllocationError<T, E, F: FnOnce() -> Result<T, E>> {
/// Error for when the entry for the handle is occupied,
/// in which case we spit out the object-provider to try again
/// with a new handle-id.
EntryOccupied(F),
/// Error for when we would exceed the maximum number of allocations.
ExceedsAllocationLimit,
+ /// Error for when the initial value-provider call failed.
+ ValueProviderFailed(E),
}
/// An individual handle-map shard, which is ultimately
@@ -116,7 +118,11 @@
// outstanding upgradeable guard on the shard. See `spin` documentation.
// Remove the pointed-to object from the map, and return it,
// releasing the lock when the guard goes out of scope.
- let removed_object = map_read_write_guard.deref_mut().remove(&handle).unwrap();
+ #[allow(clippy::expect_used)]
+ let removed_object = map_read_write_guard
+ .deref_mut()
+ .remove(&handle)
+ .expect("existence of handle is checked above");
// Decrement the allocations counter. Release ordering because we want
// to ensure that clearing the map entry never gets re-ordered to after when
// this counter gets decremented.
@@ -124,15 +130,15 @@
Ok(removed_object)
}
- pub fn try_allocate<F>(
+ pub fn try_allocate<E, F>(
&self,
handle: Handle,
object_provider: F,
outstanding_allocations_counter: &AtomicU32,
max_active_handles: u32,
- ) -> Result<(), ShardAllocationError<T, F>>
+ ) -> Result<(), ShardAllocationError<T, E, F>>
where
- F: FnOnce() -> T,
+ F: FnOnce() -> Result<T, E>,
{
let mut read_write_guard = self.data.write();
match read_write_guard.entry(handle) {
@@ -161,10 +167,17 @@
);
match allocation_count_bump_result {
Ok(_) => {
- // We're good to actually allocate
- let object = object_provider();
- vacant_entry.insert(object);
- Ok(())
+ // We're good to actually allocate,
+ // so attempt to call the value-provider.
+ match object_provider() {
+ Ok(object) => {
+ // Successfully obtained the initial value,
+ // so insert it into the vacant entry.
+ let _ = vacant_entry.insert(object);
+ Ok(())
+ }
+ Err(e) => Err(ShardAllocationError::ValueProviderFailed(e)),
+ }
}
Err(_) => {
// The allocation would cause us to exceed the allowed allocations,
diff --git a/nearby/util/handle_map/src/tests.rs b/nearby/util/handle_map/src/tests.rs
index a0774d6..90e773a 100644
--- a/nearby/util/handle_map/src/tests.rs
+++ b/nearby/util/handle_map/src/tests.rs
@@ -11,6 +11,9 @@
// 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.
+
+#![allow(clippy::unwrap_used, clippy::expect_used)]
+
use crate::*;
use core::ops::{Deref, DerefMut};
@@ -111,7 +114,7 @@
let test_fn = Arc::new(move || {
let allocation_result = handle_map_function_ref.allocate(|| 0xFF);
if let Ok(handle) = allocation_result {
- handle_map_function_ref.deallocate(handle).unwrap();
+ let _ = handle_map_function_ref.deallocate(handle).unwrap();
}
});
test_for_each_thread(test_fn, num_repetitions_per_thread);
@@ -123,7 +126,7 @@
assert_eq!((MAX_ACTIVE_HANDLES - 1) as usize, actual_num_active_handles);
//Verify that we still have space for one more entry after all that.
- handle_map_post_function_ref.allocate(|| 0xEE).unwrap();
+ let _ = handle_map_post_function_ref.allocate(|| 0xEE).unwrap();
}
/// Tests the progress of allocate/read/write/read/deallocate
@@ -219,7 +222,7 @@
let mut handle_map = build_handle_map::<u8>();
for _ in 0..(num_repetitions_per_thread * NUM_ACTIVE_THREADS) {
let handle = handle_map.allocate(|| 0xFF).expect("Initial allocations shouldn't fail");
- all_handles.insert(handle);
+ let _ = all_handles.insert(handle);
}
// Reset the new-handle-id counter
handle_map.set_new_handle_id_counter(0);
@@ -254,8 +257,9 @@
fn test_id_wraparound() {
let mut handle_map = build_handle_map::<u8>();
handle_map.set_new_handle_id_counter(u64::MAX);
- handle_map.allocate(|| 0xAB).expect("Counter wrap-around allocation should not fail");
- handle_map.allocate(|| 0xCD).expect("Post-counter-wrap-around allocation should not fail");
+ let _ = handle_map.allocate(|| 0xAB).expect("Counter wrap-around allocation should not fail");
+ let _ =
+ handle_map.allocate(|| 0xCD).expect("Post-counter-wrap-around allocation should not fail");
}
#[test]
diff --git a/nearby/util/lock_adapter/Cargo.toml b/nearby/util/lock_adapter/Cargo.toml
index eae1fc9..6e3174b 100644
--- a/nearby/util/lock_adapter/Cargo.toml
+++ b/nearby/util/lock_adapter/Cargo.toml
@@ -4,6 +4,9 @@
edition.workspace = true
publish.workspace = true
+[lints]
+workspace = true
+
[dependencies]
spin = { workspace = true, optional = true }
diff --git a/nearby/util/lock_adapter/src/lib.rs b/nearby/util/lock_adapter/src/lib.rs
index 3d75c0d..6bf6f0f 100644
--- a/nearby/util/lock_adapter/src/lib.rs
+++ b/nearby/util/lock_adapter/src/lib.rs
@@ -15,8 +15,6 @@
//! An abstraction layer for Rust synchronization primitives which provides both no_std and std library
//! based implementations
-#![forbid(unsafe_code)]
-#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
/// A Spinlock-based implementation of Mutex using the `spin` crate that can be used in `no_std`