[test] Hubris adapter traits unit test.
diff --git a/Cargo.lock b/Cargo.lock
index a590989..c1bd1b3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -68,6 +68,12 @@
 ]
 
 [[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
 name = "cfg-if"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -272,6 +278,25 @@
 ]
 
 [[package]]
+name = "hash32"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "heapless"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
+dependencies = [
+ "hash32",
+ "stable_deref_trait",
+]
+
+[[package]]
 name = "hmac"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -442,6 +467,7 @@
  "aes-gcm",
  "cipher",
  "ctr",
+ "heapless",
  "hmac",
  "k256",
  "openprot-hal-blocking",
@@ -594,6 +620,12 @@
 ]
 
 [[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
 name = "subtle"
 version = "2.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index f450a09..ff270be 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,3 +30,4 @@
 # Pin to match Hubris ecosystem
 rand_core = { version = "0.9", default-features = false }
 embedded-hal = "1.0"
+heapless = { version = "0.8", default-features = false }
diff --git a/platform/impls/rustcrypto/Cargo.toml b/platform/impls/rustcrypto/Cargo.toml
index 8b6fa78..cb54628 100644
--- a/platform/impls/rustcrypto/Cargo.toml
+++ b/platform/impls/rustcrypto/Cargo.toml
@@ -33,3 +33,4 @@
 zerocopy = { workspace = true }
 zeroize = { workspace = true }
 rand_core = { workspace = true }
+heapless = { workspace = true }
diff --git a/platform/impls/rustcrypto/src/controller.rs b/platform/impls/rustcrypto/src/controller.rs
index f1e91eb..e494709 100644
--- a/platform/impls/rustcrypto/src/controller.rs
+++ b/platform/impls/rustcrypto/src/controller.rs
@@ -22,12 +22,16 @@
 
 /// A type implementing RustCrypto-based hash/digest owned traits.
 /// Compatible with Hubris digest server requirements
-pub struct RustCryptoController {
-    // No state needed - each operation creates its own context
-}
+/// `RustCrypto`-based cryptographic controller
+///
+/// Provides software-based cryptographic operations using the `RustCrypto`
+/// ecosystem for Hubris and other embedded environments.
+pub struct RustCryptoController {}
 
 impl RustCryptoController {
-    pub fn new() -> Self {
+    /// Creates a new `RustCrypto` controller instance
+    #[must_use]
+    pub const fn new() -> Self {
         Self {}
     }
 }
@@ -534,11 +538,12 @@
 }
 
 #[cfg(test)]
+#[allow(clippy::unwrap_used)]
 mod tests {
     use super::*;
+    use heapless::Vec;
 
     #[test]
-    #[allow(clippy::unwrap_used)]
     fn test_digest_operations() {
         // Test SHA-256
         let controller = RustCryptoController::new();
@@ -677,4 +682,256 @@
         assert!(result.is_err());
         assert_eq!(result.unwrap_err(), CryptoError::InvalidKeyLength);
     }
+
+    #[test]
+    fn test_hubris_digest_integration() {
+        use openprot_platform_traits_hubris::{HubrisDigestDevice, HubrisDigestOneShot};
+
+        let controller = RustCryptoController::new();
+
+        // Test SHA-256 one-shot operation
+        let data = b"Hello, Hubris!";
+        let result = controller.digest_sha256_oneshot(data);
+        assert!(result.is_ok());
+        let digest = result.unwrap();
+        assert_eq!(digest.value.len(), 8); // 8 u32 words = 32 bytes
+
+        // Test digest context initialization
+        let controller = RustCryptoController::new();
+        let ctx_result = controller.init_digest_sha256();
+        assert!(ctx_result.is_ok());
+    }
+
+    #[test]
+    fn test_hubris_hmac_integration() {
+        use openprot_platform_traits_hubris::{HubrisDigestDevice, HubrisDigestOneShot};
+
+        let controller = RustCryptoController::new();
+        let key_data = b"test_key_123456789012345678901234"; // 32 bytes
+
+        // Test HMAC-SHA256 one-shot operation
+        let data = b"Hello, Hubris HMAC!";
+        let result = controller.hmac_sha256_oneshot(key_data, data);
+        assert!(result.is_ok());
+        let mac = result.unwrap();
+        assert_eq!(mac.len(), 32); // SHA-256 output is 32 bytes
+
+        // Test HMAC context initialization
+        let controller = RustCryptoController::new();
+        let key = SecureOwnedKey::new(key_data).unwrap();
+        let ctx_result = controller.init_hmac_sha256(key);
+        assert!(ctx_result.is_ok());
+    }
+
+    #[test]
+    fn test_hubris_key_creation() {
+        use openprot_platform_traits_hubris::HubrisDigestDevice;
+
+        // Test key creation with valid sizes
+        let small_key = b"small";
+        let result = RustCryptoController::create_hmac_key(small_key);
+        assert!(result.is_ok());
+
+        // Test with maximum key size using heapless::Vec for realistic embedded testing
+        let mut max_key: Vec<u8, 256> = Vec::new(); // heapless::Vec with capacity 256
+        max_key
+            .resize(RustCryptoController::MAX_KEY_SIZE, 0)
+            .unwrap();
+        let result = RustCryptoController::create_hmac_key(&max_key);
+        assert!(result.is_ok());
+
+        // Test key creation with oversized key
+        let mut oversized_key: Vec<u8, 256> = Vec::new();
+        oversized_key
+            .resize(RustCryptoController::MAX_KEY_SIZE + 1, 0)
+            .unwrap();
+        let result = RustCryptoController::create_hmac_key(&oversized_key);
+        assert!(result.is_err());
+    }
+
+    #[test]
+    fn test_hubris_error_mapping() {
+        use openprot_platform_traits_hubris::{HubrisCryptoError, HubrisDigestDevice};
+
+        // Test error mapping for oversized keys using heapless::Vec
+        let mut oversized_key: Vec<u8, 256> = Vec::new();
+        oversized_key
+            .resize(RustCryptoController::MAX_KEY_SIZE + 1, 0)
+            .unwrap();
+        let result = RustCryptoController::create_hmac_key(&oversized_key);
+        assert_eq!(result.unwrap_err(), HubrisCryptoError::InvalidKeyLength);
+    }
+
+    #[test]
+    fn test_hubris_sha256_correctness() {
+        use openprot_platform_traits_hubris::HubrisDigestOneShot;
+
+        let controller = RustCryptoController::new();
+
+        // Test with known SHA-256 test vector
+        // Input: "abc"
+        // Expected SHA-256: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
+        let data = b"abc";
+        let result = controller.digest_sha256_oneshot(data).unwrap();
+
+        // Use the proper as_bytes() method for comparison
+        let digest_bytes = result.as_bytes();
+
+        let expected = [
+            0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
+            0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
+            0xf2, 0x00, 0x15, 0xad,
+        ];
+
+        assert_eq!(
+            digest_bytes, expected,
+            "SHA-256 digest does not match expected test vector"
+        );
+    }
+
+    #[test]
+    fn test_hubris_hmac_sha256_correctness() {
+        use openprot_platform_traits_hubris::HubrisDigestOneShot;
+
+        let controller = RustCryptoController::new();
+
+        // Test with known HMAC-SHA256 test vector from RFC 4231
+        // Key: "key" (0x6b6579)
+        // Data: "The quick brown fox jumps over the lazy dog"
+        // Expected: f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
+        let key = b"key";
+        let data = b"The quick brown fox jumps over the lazy dog";
+
+        let result = controller.hmac_sha256_oneshot(key, data).unwrap();
+
+        let expected = [
+            0xf7, 0xbc, 0x83, 0xf4, 0x30, 0x53, 0x84, 0x24, 0xb1, 0x32, 0x98, 0xe6, 0xaa, 0x6f,
+            0xb1, 0x43, 0xef, 0x4d, 0x59, 0xa1, 0x49, 0x46, 0x17, 0x59, 0x97, 0x47, 0x9d, 0xbc,
+            0x2d, 0x1a, 0x3c, 0xd8,
+        ];
+
+        assert_eq!(
+            result, expected,
+            "HMAC-SHA256 does not match expected test vector"
+        );
+    }
+
+    #[test]
+    fn test_hubris_digest_context_operations() {
+        use openprot_hal_blocking::digest::owned::DigestOp;
+        use openprot_platform_traits_hubris::HubrisDigestDevice;
+
+        let controller = RustCryptoController::new();
+
+        // Test incremental hashing with known result
+        // Hash "abc" in parts: "a" + "bc"
+        let ctx = controller.init_digest_sha256().unwrap();
+        let ctx = ctx.update(b"a").unwrap();
+        let ctx = ctx.update(b"bc").unwrap();
+        let (result, _controller) = ctx.finalize().unwrap();
+
+        // Should match the same result as hashing "abc" at once
+        let digest_bytes = result.as_bytes();
+
+        let expected = [
+            0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
+            0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
+            0xf2, 0x00, 0x15, 0xad,
+        ];
+
+        assert_eq!(
+            digest_bytes, expected,
+            "Incremental SHA-256 digest does not match expected result"
+        );
+    }
+
+    #[test]
+    fn test_hubris_hmac_context_operations() {
+        use openprot_hal_blocking::mac::owned::MacOp;
+        use openprot_platform_traits_hubris::HubrisDigestDevice;
+
+        let controller = RustCryptoController::new();
+        let key_data = b"key";
+        let key = SecureOwnedKey::new(key_data).unwrap();
+
+        // Test incremental HMAC with known result
+        // HMAC "The quick brown fox jumps over the lazy dog" in parts
+        let ctx = controller.init_hmac_sha256(key).unwrap();
+        let ctx = ctx.update(b"The quick brown fox ").unwrap();
+        let ctx = ctx.update(b"jumps over the lazy dog").unwrap();
+        let (result, _controller) = ctx.finalize().unwrap();
+
+        let expected = [
+            0xf7, 0xbc, 0x83, 0xf4, 0x30, 0x53, 0x84, 0x24, 0xb1, 0x32, 0x98, 0xe6, 0xaa, 0x6f,
+            0xb1, 0x43, 0xef, 0x4d, 0x59, 0xa1, 0x49, 0x46, 0x17, 0x59, 0x97, 0x47, 0x9d, 0xbc,
+            0x2d, 0x1a, 0x3c, 0xd8,
+        ];
+
+        assert_eq!(
+            result, expected,
+            "Incremental HMAC-SHA256 does not match expected result"
+        );
+    }
+
+    #[test]
+    fn test_hubris_comprehensive_crypto_demo() {
+        use openprot_hal_blocking::digest::owned::DigestOp;
+        use openprot_hal_blocking::mac::owned::MacOp;
+        use openprot_platform_traits_hubris::{HubrisDigestDevice, HubrisDigestOneShot};
+
+        // Test 1: SHA-256 One-shot
+        let controller = RustCryptoController::new();
+        let message = b"Hello, Hubris crypto world!";
+        let digest = controller.digest_sha256_oneshot(message).unwrap();
+        assert_eq!(digest.as_bytes().len(), 32); // SHA-256 produces 32 bytes
+
+        // Test 2: Incremental SHA-256
+        let controller = RustCryptoController::new();
+        let ctx = controller.init_digest_sha256().unwrap();
+        let ctx = ctx.update(b"Hello, ").unwrap();
+        let ctx = ctx.update(b"Hubris crypto ").unwrap();
+        let ctx = ctx.update(b"world!").unwrap();
+        let (digest_inc, _controller_recovered) = ctx.finalize().unwrap();
+        assert_eq!(digest.as_bytes(), digest_inc.as_bytes());
+
+        // Test 3: HMAC-SHA256 One-shot
+        let controller = RustCryptoController::new();
+        let key_data = b"secure_key_for_hubris_testing_123";
+        let hmac = controller.hmac_sha256_oneshot(key_data, message).unwrap();
+        assert_eq!(hmac.len(), 32); // HMAC-SHA256 produces 32 bytes
+
+        // Test 4: Incremental HMAC-SHA256
+        let controller = RustCryptoController::new();
+        let key = SecureOwnedKey::new(key_data).unwrap();
+        let ctx = controller.init_hmac_sha256(key).unwrap();
+        let ctx = ctx.update(b"Hello, ").unwrap();
+        let ctx = ctx.update(b"Hubris crypto ").unwrap();
+        let ctx = ctx.update(b"world!").unwrap();
+        let (hmac_inc, _controller_recovered) = ctx.finalize().unwrap();
+        assert_eq!(hmac, hmac_inc);
+
+        // Test 5: Key Management with heapless::Vec (embedded-friendly)
+        let mut dynamic_key: Vec<u8, 64> = Vec::new();
+        dynamic_key
+            .extend_from_slice(b"dynamic_embedded_key")
+            .unwrap();
+        let key_result = RustCryptoController::create_hmac_key(&dynamic_key);
+        assert!(key_result.is_ok());
+
+        // Test 6: Error handling with oversized keys
+        let mut oversized_key: Vec<u8, 256> = Vec::new();
+        oversized_key
+            .resize(RustCryptoController::MAX_KEY_SIZE + 1, 0)
+            .unwrap();
+        let error_result = RustCryptoController::create_hmac_key(&oversized_key);
+        assert!(error_result.is_err());
+
+        // All operations completed successfully - demonstrates that:
+        // ✅ RustCrypto backend is fully functional
+        // ✅ Hubris platform traits properly implemented
+        // ✅ Memory-safe operations in no_std environment
+        // ✅ Cryptographically correct results verified
+        // ✅ heapless::Vec integration working
+        // ✅ Controller recovery after operations working
+    }
 }