From f0e5fc3cbefc03e7645c25f63dbcd7cd495c5ea7 Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sat, 22 Nov 2025 17:20:58 -0500 Subject: [PATCH 1/8] add tokio --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 5d2a5de..ad8462d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ hkdf = "0.12.4" chacha20poly1305 = "0.10.1" slh-dsa = "0.0.3" ml-kem = "0.2.1" +tokio = "1.48.0" [profile.dev.package.num-bigint-dig] opt-level = 3 From 8222cc7a2445991201232847dd0b12e4143a3277 Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sat, 22 Nov 2025 19:15:37 -0500 Subject: [PATCH 2/8] adding debug --- .vscode/launch.json | 249 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e3aa5a0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,249 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug unit tests in library 'cas_lib'", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--lib", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": [ + "--nocapture" + ], + "cwd": "${workspaceFolder}", + "env": { + "RUST_BACKTRACE": "1" + }, + "console": "integratedTerminal" + }, + + // Integration tests + { + "name": "Debug integration test: asymmetric", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=asymmetric", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: compression", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=compression", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: digital_signatures", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=digital_signatures", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: hashers", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=hashers", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: http", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=http", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: hybrid", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=hybrid", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: key_exchange", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=key_exchange", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: message", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=message", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: password_hashers", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=password_hashers", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: pqc", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=pqc", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: signatures", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=signatures", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: sponges", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=sponges", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + }, + { + "name": "Debug integration test: symmetric", + "type": "lldb", + "request": "launch", + "cargo": { + "args": [ + "test", + "--test=symmetric", + "--no-run" + ] + }, + "program": "${cargo:program}", + "args": ["--nocapture"], + "cwd": "${workspaceFolder}", + "env": { "RUST_BACKTRACE": "1" }, + "console": "integratedTerminal" + } + ] +} \ No newline at end of file From 6f3a8e0b18fd3fc273abf412e07312525fe34d3b Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sat, 22 Nov 2025 19:16:10 -0500 Subject: [PATCH 3/8] basic benchmark sender --- Cargo.toml | 3 +++ src/http/mod.rs | 27 +++++++++++++++++++++++++++ src/lib.rs | 4 +++- tests/http.rs | 10 ++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/http/mod.rs create mode 100644 tests/http.rs diff --git a/Cargo.toml b/Cargo.toml index ad8462d..fb939a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,9 @@ chacha20poly1305 = "0.10.1" slh-dsa = "0.0.3" ml-kem = "0.2.1" tokio = "1.48.0" +reqwest = { version = "0.12.24", features = ["json"] } +serde = "1.0.228" +tokio = { version = "1.48.0", features = ["macros"] } [profile.dev.package.num-bigint-dig] opt-level = 3 diff --git a/src/http/mod.rs b/src/http/mod.rs new file mode 100644 index 0000000..d64fd60 --- /dev/null +++ b/src/http/mod.rs @@ -0,0 +1,27 @@ +use reqwest::{Client, Response}; +use tokio::task; +use serde::Serialize; + + +#[derive(Serialize)] +struct BenchmarkRequest { + name: String, + time_in_milliseconds: i64 +} + +pub async fn send_benchmark(algorithm_name: String, time_in_milliseconds: i64) -> Response { + let client = Client::new(); + let payload = BenchmarkRequest { + name: algorithm_name, + time_in_milliseconds + }; + + // Spawn a background task + let response_task = task::spawn(async move { + client.post("http://localhost:5000/api/Benchmark") + .json(&payload) + .send() + .await + }); + return response_task.await.unwrap().unwrap(); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 65b9cfa..58136d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,4 +62,6 @@ pub mod pqc { pub mod ml_kem; pub mod cas_pqc; pub mod slh_dsa; -} \ No newline at end of file +} + +pub mod http; \ No newline at end of file diff --git a/tests/http.rs b/tests/http.rs new file mode 100644 index 0000000..3436663 --- /dev/null +++ b/tests/http.rs @@ -0,0 +1,10 @@ +#[cfg(test)] +mod http { + use cas_lib::http::send_benchmark; + + #[tokio::test] + async fn test_send_fire_and_forget() { + // Since the function is fire-and-forget, we just ensure it runs without panicking. + send_benchmark(String::from("My Name"), 42).await; + } +} \ No newline at end of file From dbf691a68239b163623dc20c6a2487e1304e83c8 Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sun, 23 Nov 2025 11:54:00 -0500 Subject: [PATCH 4/8] adding basic http cache and benchmark sender --- Cargo.toml | 5 ++- src/http/mod.rs | 89 ++++++++++++++++++++++++++++++++++++------- src/http/types/mod.rs | 16 ++++++++ 3 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 src/http/types/mod.rs diff --git a/Cargo.toml b/Cargo.toml index fb939a0..eb112fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,13 +34,14 @@ hkdf = "0.12.4" chacha20poly1305 = "0.10.1" slh-dsa = "0.0.3" ml-kem = "0.2.1" -tokio = "1.48.0" -reqwest = { version = "0.12.24", features = ["json"] } +reqwest = { version = "0.12.24", features = ["json", "cookies", "rustls-tls"] } serde = "1.0.228" tokio = { version = "1.48.0", features = ["macros"] } +url = "2.5.7" [profile.dev.package.num-bigint-dig] opt-level = 3 [build-dependencies] napi-build = "1" + diff --git a/src/http/mod.rs b/src/http/mod.rs index d64fd60..bb8b2f8 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -1,27 +1,90 @@ -use reqwest::{Client, Response}; +use reqwest::{cookie::Jar, Client, Response}; +use std::sync::{Arc, Mutex}; use tokio::task; -use serde::Serialize; +use url::Url; +pub mod types; +use crate::http::types::BenchmarkRequest; -#[derive(Serialize)] -struct BenchmarkRequest { - name: String, - time_in_milliseconds: i64 +static API_KEY: Mutex = Mutex::new(String::new()); +static BASE_URL: Mutex = Mutex::new(String::new()); + +static TOKEN: Mutex = Mutex::new(String::new()); +static REFRESH_TOKEN: Mutex = Mutex::new(String::new()); +static BENCHMARK_SENDER_CLIENT: Mutex> = Mutex::new(None); + +fn create_benchmark_sender_client(token: String, refresh_token: String) -> Client { + let cookie_store = Arc::new(Jar::default()); + let base_url = Url::parse(BASE_URL.lock().unwrap().as_str()).unwrap(); + cookie_store.add_cookie_str(&format!("Token={}; Path=/", token), &base_url); + cookie_store.add_cookie_str(&format!("RefreshToken={}; Path=/", refresh_token), &base_url); + Client::builder() + .cookie_provider(cookie_store) + .build() + .unwrap() +} + +fn determine_api_route() -> String { + let base_url = BASE_URL.lock().unwrap(); + if base_url.contains("cryptographicapiservices.com") { + "api/userapi".to_string() + } else { + "api".to_string() + } +} + +pub async fn set_api_key_in_cache(api_key: String) { + let mut key = API_KEY.lock().unwrap(); + *key = api_key.clone(); + set_tokens_in_cache(api_key).await; } -pub async fn send_benchmark(algorithm_name: String, time_in_milliseconds: i64) -> Response { +pub async fn set_base_url_in_cache(base_url: String) { + let mut url = BASE_URL.lock().unwrap(); + *url = base_url +} + +async fn set_tokens_in_cache(api_key: String) { let client = Client::new(); + let testing = BASE_URL.lock().unwrap().clone(); + let url = format!("{}/{}/APIKey/GetToken", testing, determine_api_route()); + let response_task = client + .get(url) + .header("Authorization", api_key) + .send() + .await; + let response = response_task.unwrap().json::(); + let mut token = TOKEN.lock().unwrap(); + let mut refresh_token = REFRESH_TOKEN.lock().unwrap(); + let mut bench_mark_client = BENCHMARK_SENDER_CLIENT.lock().unwrap(); + match response.await { + Ok(auth_response) => { + *token = auth_response.token.clone(); + *refresh_token = auth_response.refresh_token.clone(); + *bench_mark_client = Some(create_benchmark_sender_client(auth_response.token, auth_response.refresh_token)); + } + Err(_) => { + *token = String::new(); + *refresh_token = String::new(); + } + } +} + +pub async fn send_benchmark(time_in_milliseconds: i64, class_name: String, method_name: String) -> Response { let payload = BenchmarkRequest { - name: algorithm_name, - time_in_milliseconds + class_name, + method_name, + time_in_milliseconds, }; - // Spawn a background task - let response_task = task::spawn(async move { - client.post("http://localhost:5000/api/Benchmark") + let response = task::spawn(async move { + let base_url = BASE_URL.lock().unwrap().clone(); + let client = BENCHMARK_SENDER_CLIENT.lock().unwrap().as_ref().unwrap().clone(); + client + .post(format!("{}/{}/Benchmark", base_url, determine_api_route())) .json(&payload) .send() .await }); - return response_task.await.unwrap().unwrap(); + response.await.unwrap().unwrap() } \ No newline at end of file diff --git a/src/http/types/mod.rs b/src/http/types/mod.rs new file mode 100644 index 0000000..059cf23 --- /dev/null +++ b/src/http/types/mod.rs @@ -0,0 +1,16 @@ +use serde::Serialize; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct BenchmarkRequest { + pub class_name: String, + pub method_name: String, + pub time_in_milliseconds: i64 +} + +#[derive(serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthResponse { + pub token: String, + pub refresh_token: String +} \ No newline at end of file From 152edb7fe11c094d928b6a8a252b8075682de0db Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sun, 23 Nov 2025 11:54:20 -0500 Subject: [PATCH 5/8] version bump --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index eb112fb..986193f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cas-lib" -version = "0.2.66" +version = "0.2.67" edition = "2021" description = "A function wrapper layer for RustCrypto and Dalek-Cryptography. Intended to be used in FFI situations with a global heap deallactor at the top level project." license = "Apache-2.0" From ddee6444fec321ed31c2832df4a930f134270a0f Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sun, 23 Nov 2025 11:55:21 -0500 Subject: [PATCH 6/8] task spawn --- src/http/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/http/mod.rs b/src/http/mod.rs index bb8b2f8..6e12444 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -70,14 +70,14 @@ async fn set_tokens_in_cache(api_key: String) { } } -pub async fn send_benchmark(time_in_milliseconds: i64, class_name: String, method_name: String) -> Response { +pub async fn send_benchmark(time_in_milliseconds: i64, class_name: String, method_name: String) { let payload = BenchmarkRequest { class_name, method_name, time_in_milliseconds, }; // Spawn a background task - let response = task::spawn(async move { + task::spawn(async move { let base_url = BASE_URL.lock().unwrap().clone(); let client = BENCHMARK_SENDER_CLIENT.lock().unwrap().as_ref().unwrap().clone(); client @@ -86,5 +86,4 @@ pub async fn send_benchmark(time_in_milliseconds: i64, class_name: String, metho .send() .await }); - response.await.unwrap().unwrap() } \ No newline at end of file From d699c8c14e4396888aaac6047dfe9b3c07280b06 Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sun, 23 Nov 2025 15:46:47 -0500 Subject: [PATCH 7/8] bench mark sending --- Cargo.toml | 3 +- src/http/mod.rs | 61 ++++++++++++++++++++++----------------- src/http/types/mod.rs | 2 ++ src/http/types/runtime.rs | 11 +++++++ 4 files changed, 49 insertions(+), 28 deletions(-) create mode 100644 src/http/types/runtime.rs diff --git a/Cargo.toml b/Cargo.toml index 986193f..5f24576 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,8 +36,9 @@ slh-dsa = "0.0.3" ml-kem = "0.2.1" reqwest = { version = "0.12.24", features = ["json", "cookies", "rustls-tls"] } serde = "1.0.228" -tokio = { version = "1.48.0", features = ["macros"] } +tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread"] } url = "2.5.7" +once_cell = "1.21.3" [profile.dev.package.num-bigint-dig] opt-level = 3 diff --git a/src/http/mod.rs b/src/http/mod.rs index 6e12444..1a5732c 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -1,10 +1,9 @@ -use reqwest::{cookie::Jar, Client, Response}; +use reqwest::{Client, cookie::Jar}; use std::sync::{Arc, Mutex}; -use tokio::task; use url::Url; pub mod types; -use crate::http::types::BenchmarkRequest; +use crate::http::types::{BenchmarkRequest}; static API_KEY: Mutex = Mutex::new(String::new()); static BASE_URL: Mutex = Mutex::new(String::new()); @@ -39,33 +38,43 @@ pub async fn set_api_key_in_cache(api_key: String) { set_tokens_in_cache(api_key).await; } -pub async fn set_base_url_in_cache(base_url: String) { +pub fn set_base_url_in_cache(base_url: String) { let mut url = BASE_URL.lock().unwrap(); *url = base_url } -async fn set_tokens_in_cache(api_key: String) { +pub async fn set_tokens_in_cache(api_key: String) { let client = Client::new(); - let testing = BASE_URL.lock().unwrap().clone(); - let url = format!("{}/{}/APIKey/GetToken", testing, determine_api_route()); + let base_url = BASE_URL.lock().unwrap().clone(); + let url = format!("{}/{}/APIKey/GetToken", base_url, determine_api_route()); let response_task = client .get(url) .header("Authorization", api_key) .send() .await; - let response = response_task.unwrap().json::(); - let mut token = TOKEN.lock().unwrap(); - let mut refresh_token = REFRESH_TOKEN.lock().unwrap(); - let mut bench_mark_client = BENCHMARK_SENDER_CLIENT.lock().unwrap(); - match response.await { + let response = response_task.unwrap().json::().await; + match response { Ok(auth_response) => { - *token = auth_response.token.clone(); - *refresh_token = auth_response.refresh_token.clone(); - *bench_mark_client = Some(create_benchmark_sender_client(auth_response.token, auth_response.refresh_token)); + { + let mut token = TOKEN.lock().unwrap(); + *token = auth_response.token.clone(); + } + { + let mut refresh = REFRESH_TOKEN.lock().unwrap(); + *refresh = auth_response.refresh_token.clone(); + } + { + let mut bench_client = BENCHMARK_SENDER_CLIENT.lock().unwrap(); + *bench_client = Some(create_benchmark_sender_client( + auth_response.token, + auth_response.refresh_token, + )); + } } + Err(_) => { - *token = String::new(); - *refresh_token = String::new(); + *TOKEN.lock().unwrap() = String::new(); + *REFRESH_TOKEN.lock().unwrap() = String::new(); } } } @@ -76,14 +85,12 @@ pub async fn send_benchmark(time_in_milliseconds: i64, class_name: String, metho method_name, time_in_milliseconds, }; - // Spawn a background task - task::spawn(async move { - let base_url = BASE_URL.lock().unwrap().clone(); - let client = BENCHMARK_SENDER_CLIENT.lock().unwrap().as_ref().unwrap().clone(); - client - .post(format!("{}/{}/Benchmark", base_url, determine_api_route())) - .json(&payload) - .send() - .await - }); + let base_url = BASE_URL.lock().unwrap().clone(); + let client = BENCHMARK_SENDER_CLIENT.lock().unwrap().as_ref().unwrap().clone(); + + let response = client + .post(format!("{}/{}/Benchmark", base_url, determine_api_route())) + .json(&payload) + .send() + .await; } \ No newline at end of file diff --git a/src/http/types/mod.rs b/src/http/types/mod.rs index 059cf23..419ffa9 100644 --- a/src/http/types/mod.rs +++ b/src/http/types/mod.rs @@ -1,5 +1,7 @@ use serde::Serialize; +pub mod runtime; + #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct BenchmarkRequest { diff --git a/src/http/types/runtime.rs b/src/http/types/runtime.rs new file mode 100644 index 0000000..60d1bfc --- /dev/null +++ b/src/http/types/runtime.rs @@ -0,0 +1,11 @@ + +use once_cell::sync::Lazy; +use tokio::runtime::Runtime; + +pub static RUNTIME: Lazy = Lazy::new(|| { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(4) + .build() + .unwrap() +}); \ No newline at end of file From beeb9dae7c15c46662b10644cf6453aa607d0c9c Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sun, 23 Nov 2025 17:32:07 -0500 Subject: [PATCH 8/8] remove http test --- tests/http.rs | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 tests/http.rs diff --git a/tests/http.rs b/tests/http.rs deleted file mode 100644 index 3436663..0000000 --- a/tests/http.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[cfg(test)] -mod http { - use cas_lib::http::send_benchmark; - - #[tokio::test] - async fn test_send_fire_and_forget() { - // Since the function is fire-and-forget, we just ensure it runs without panicking. - send_benchmark(String::from("My Name"), 42).await; - } -} \ No newline at end of file