#encryption #serialization

runar-serializer

Enhanced serialization with selective field encryption for Runar

1 unstable release

0.1.0 Aug 14, 2025

#978 in Encoding

Download history 122/week @ 2025-08-13 39/week @ 2025-08-20 29/week @ 2025-08-27 41/week @ 2025-09-03 24/week @ 2025-09-10 17/week @ 2025-09-17 30/week @ 2025-09-24 45/week @ 2025-10-01 10/week @ 2025-10-08 40/week @ 2025-10-15 30/week @ 2025-10-22

126 downloads per month
Used in 8 crates (7 directly)

MIT license

225KB
4K SLoC

runar-serializer

Typed values with optional, selective field encryption for Runar apps and services. Provides a compact, clone-efficient ArcValue container and pluggable encryption via a SerializationContext (network/profile keys).

Install

[dependencies]
runar-serializer = "0.1"

Highlights

  • ArcValue: typed, clone-efficient container with JSON/CBOR/Proto support
  • Pluggable crypto: transparent encryption/decryption when a SerializationContext is provided
  • Derives: works with runar-serializer-macros (Encrypt, Plain)

Quick start

use runar_serializer::{ArcValue, ValueCategory};

#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
struct User { id: String, name: String }

let av = ArcValue::new_struct(User { id: "1".into(), name: "alice".into() });
assert_eq!(av.category(), ValueCategory::Struct);

// No encryption
let bytes = av.serialize(None)?;
let roundtrip = ArcValue::deserialize(&bytes, None)?;
let user: std::sync::Arc<User> = roundtrip.as_struct_ref()?;

Field‑level encryption (abridged)

Combine this crate with runar-serializer-macros and runar-keys to encrypt specific fields for user/profile or system/network contexts.

use std::collections::HashMap;
use std::sync::Arc;
use runar_common::logging::{Component, Logger};
use runar_keys::{MobileKeyManager, NodeKeyManager};
use runar_serializer::{
    traits::{
        ConfigurableLabelResolver, EnvelopeCrypto, KeyMappingConfig, LabelKeyInfo,
        SerializationContext,
    },
    ArcValue,
};
use runar_serializer_macros::Encrypt;

#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize, Encrypt)]
struct Profile {
    id: String,
    #[runar(system)] name: String,
    #[runar(user)] private: String,
    #[runar(search)] email: String,
    #[runar(system_only)] system_metadata: String,
}

// Prepare keystores and resolver
let logger = Arc::new(Logger::new_root(Component::System, "readme-example"));
let mut network_master = MobileKeyManager::new(logger.clone())?;
let network_id = network_master.generate_network_data_key()?;
let network_pub = network_master.get_network_public_key(&network_id)?;

let mut user_mobile = MobileKeyManager::new(logger.clone())?;
user_mobile.initialize_user_root_key()?;
let profile_pk = user_mobile.derive_user_profile_key("default")?;
user_mobile.install_network_public_key(&network_pub)?;

let mut node = NodeKeyManager::new(logger.clone())?;
let token = node.generate_csr()?;
let nk_msg = network_master.create_network_key_message(&network_id, &token.node_agreement_public_key)?;
node.install_network_key(nk_msg)?;

let resolver = Arc::new(ConfigurableLabelResolver::new(KeyMappingConfig {
    label_mappings: HashMap::from([
        ("user".into(),        LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: None }),
        ("system".into(),      LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: Some(network_id.clone()) }),
        ("system_only".into(), LabelKeyInfo { profile_public_keys: vec![],                    network_id: Some(network_id.clone()) }),
        ("search".into(),      LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: Some(network_id.clone()) }),
    ]),
}));

let mobile_ks = Arc::new(user_mobile) as Arc<dyn EnvelopeCrypto>;
let node_ks = Arc::new(node) as Arc<dyn EnvelopeCrypto>;

let profile = Profile { id: "123".into(), name: "User".into(), private: "secret".into(), email: "u@example.com".into(), system_metadata: "sys".into() };

// Encrypt to generated EncryptedProfile
let enc: EncryptedProfile = profile.encrypt_with_keystore(&mobile_ks, resolver.as_ref())?;
// Decrypt in different contexts
let _mobile_view = enc.decrypt_with_keystore(&mobile_ks)?; // user fields available
let _node_view = enc.decrypt_with_keystore(&node_ks)?;     // system fields available

// ArcValue integration with transparent encryption on serialize
let ctx = SerializationContext { keystore: mobile_ks, resolver, network_id, profile_public_key: Some(profile_pk) };
let av = ArcValue::new_struct(Profile { id: "1".into(), name: "Alice".into(), private: "s".into(), email: "a@ex".into(), system_metadata: "m".into() });
let ser = av.serialize(Some(&ctx))?;              // encrypted
let de = ArcValue::deserialize(&ser, Some(node_ks))?; // decrypted for node

Plain derive (zero glue)

Use #[derive(Plain)] from runar-serializer-macros to implement efficient conversions to/from ArcValue.

use runar_serializer::ArcValue;
use runar_serializer_macros::Plain;

#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize, Plain)]
struct Simple { a: i64, b: String }

let av = ArcValue::new_struct(Simple { a: 7, b: "x".into() });
let extracted: std::sync::Arc<Simple> = av.as_struct_ref()?;

License

MIT. See LICENSE.

Dependencies

~24–41MB
~731K SLoC