distribute/crypto/types
Crypto layer type definitions.
This module contains all shared types used by crypto providers. These types form the contract between the provider implementations and the higher-level crypto facade.
Type Categories
- Handles - Opaque references to running providers
- Contexts - Secure contexts for encrypt/decrypt
- Status - Health and metrics
- Errors - Structured error types
Types
Errors from crypto operations.
pub type CryptoError {
NotInitialized
InitFailed(reason: String)
ShutdownFailed(reason: String)
TransientNetwork(reason: String)
InvalidSignature
KeyMismatch
DecryptionFailed(reason: String)
EncryptionFailed(reason: String)
NoSecureContext(node: String)
HandshakeFailed(reason: String)
RekeyFailed(reason: String)
ProviderFailure(reason: String)
Timeout(elapsed_ms: Int)
}
Constructors
-
NotInitializedProvider not initialized
-
InitFailed(reason: String)Initialization failed
-
ShutdownFailed(reason: String)Shutdown failed
-
TransientNetwork(reason: String)Transient network error
-
InvalidSignatureInvalid signature
-
KeyMismatchKey mismatch
-
DecryptionFailed(reason: String)Decryption failed
-
EncryptionFailed(reason: String)Encryption failed
-
NoSecureContext(node: String)No secure context for node
-
HandshakeFailed(reason: String)Handshake failed
-
RekeyFailed(reason: String)Rekey failed
-
ProviderFailure(reason: String)Internal provider error
-
Timeout(elapsed_ms: Int)Operation timed out
Crypto provider metrics.
pub type CryptoMetrics {
CryptoMetrics(
handshakes_initiated: Int,
handshakes_completed: Int,
handshakes_failed: Int,
encrypt_count: Int,
decrypt_count: Int,
rekey_count: Int,
active_contexts: Int,
)
}
Constructors
-
CryptoMetrics( handshakes_initiated: Int, handshakes_completed: Int, handshakes_failed: Int, encrypt_count: Int, decrypt_count: Int, rekey_count: Int, active_contexts: Int, )
Message exchanged during handshake.
pub type HandshakeMessage {
HandshakeMessage(
message_type: String,
payload: BitArray,
metadata: option.Option(dict.Dict(String, String)),
)
}
Constructors
-
HandshakeMessage( message_type: String, payload: BitArray, metadata: option.Option(dict.Dict(String, String)), )
Result of a handshake step.
pub type HandshakeResult {
Continue(
state: HandshakeState,
response: option.Option(HandshakeMessage),
)
Established(context: SecureContext)
HandshakeError(error: CryptoError)
}
Constructors
-
Continue( state: HandshakeState, response: option.Option(HandshakeMessage), )Continue handshake with optional response
-
Established(context: SecureContext)Handshake completed
-
HandshakeError(error: CryptoError)Handshake failed
Handshake state machine stages.
pub type HandshakeStage {
Plain
KeyExchangeInProgress
SecureEstablished
Rekeying
Failed(reason: String)
}
Constructors
-
PlainNo secure context established
-
KeyExchangeInProgressKey exchange in progress
-
SecureEstablishedSecure context established
-
RekeyingRekeying in progress
-
Failed(reason: String)Handshake failed
Intermediate state during handshake.
pub opaque type HandshakeState
Health status of a crypto provider.
pub type HealthStatus {
Up
Degraded(reason: String)
Down(reason: String)
}
Constructors
-
UpProvider is fully operational
-
Degraded(reason: String)Provider is degraded
-
Down(reason: String)Provider is down
Opaque handle representing an active crypto provider instance.
Created by adapter.init() and required for all subsequent operations.
pub opaque type ProviderHandle
Options for initializing a crypto provider.
pub type ProviderOptions {
ProviderOptions(
name: String,
is_development: Bool,
key_rotation_interval_ms: Int,
handshake_timeout_ms: Int,
custom: dict.Dict(String, String),
)
}
Constructors
-
ProviderOptions( name: String, is_development: Bool, key_rotation_interval_ms: Int, handshake_timeout_ms: Int, custom: dict.Dict(String, String), )
Opaque secure context for encrypt/decrypt operations.
Security Note: Never log or serialize the internal contents.
pub opaque type SecureContext
Values
pub fn context_created_at(ctx: SecureContext) -> Int
Get the creation timestamp.
Returns the timestamp (in milliseconds since epoch) when this secure context was created. Useful for implementing key rotation policies based on context age.
Example
let age_ms = now_ms() - types.context_created_at(ctx)
case age_ms > max_key_age_ms {
True -> crypto.rekey(node_id)
False -> Ok(Nil)
}
pub fn context_key_id(ctx: SecureContext) -> String
Get the key ID (for logging/debugging without exposing key material).
Returns a unique identifier for the current encryption key. This ID changes after each rekey operation and can be safely logged for debugging purposes without exposing actual key material.
Example
log.debug("Using key: " <> types.context_key_id(ctx))
pub fn context_key_material(
ctx: SecureContext,
) -> dynamic.Dynamic
Get the key material (provider internal use only).
Returns the opaque key material for encryption/decryption. This is provider-specific and typically contains AEAD keys and master secrets.
WARNING: Security-sensitive function
- Never log the returned value
- Never serialize or transmit it
- Only use within provider implementations
- Provider should zero memory when context is destroyed
pub fn context_node_id(ctx: SecureContext) -> String
Get the node ID from a secure context.
Returns the identifier of the remote node this context was established with. Use this to verify you’re using the correct context for a message.
Example
let node = types.context_node_id(ctx)
case node == expected_sender {
True -> decrypt(ctx, message)
False -> Error(WrongContext)
}
pub fn context_stage(ctx: SecureContext) -> HandshakeStage
Get the handshake stage.
Returns the current stage of the handshake state machine. A context
should only be used for encryption when the stage is SecureEstablished.
Stages
Plain- No security establishedKeyExchangeInProgress- Handshake ongoingSecureEstablished- Ready for encryptionRekeying- Key rotation in progressFailed(reason)- Handshake failed
pub fn empty_metrics() -> CryptoMetrics
Default empty metrics.
Returns a CryptoMetrics struct with all counters initialized to zero.
Useful as a fallback when metrics cannot be retrieved from a provider.
Example
let metrics = case adapter.metrics(handle) {
Ok(m) -> m
Error(_) -> types.empty_metrics()
}
pub fn handle_id(handle: ProviderHandle) -> String
Get the handle’s identifier.
Returns the unique identifier assigned to this provider handle during creation. Useful for logging, debugging, and registry lookups.
Example
let id = types.handle_id(handle)
io.println("Provider: " <> id)
pub fn handle_state(handle: ProviderHandle) -> dynamic.Dynamic
Get the handle’s internal state.
Returns the opaque internal state of the provider. This is typically the actor subject used for message passing.
Internal use only - Provider implementations use this to extract the actor subject for sending commands.
Security Note
Never log or serialize the returned Dynamic as it may contain references to sensitive cryptographic state.
pub fn handshake_data(state: HandshakeState) -> dynamic.Dynamic
Get handshake data (provider internal).
Returns the provider-specific handshake data. This typically contains ephemeral keypairs and peer public keys needed to complete the key exchange.
Internal use only - For provider implementations.
pub fn handshake_local_node(state: HandshakeState) -> String
Get local node.
Returns the identifier of the local node in this handshake.
pub fn handshake_remote_node(state: HandshakeState) -> String
Get remote node.
Returns the identifier of the remote node this handshake is being conducted with. Used for context lookup and message routing.
pub fn handshake_stage(state: HandshakeState) -> HandshakeStage
Get handshake stage.
Returns the current stage of the handshake state machine for this handshake operation. Used to determine if more message exchanges are needed or if the handshake has completed/failed.
Returns
KeyExchangeInProgress- More exchanges neededSecureEstablished- Handshake completeFailed(reason)- Handshake failed
pub fn is_permanent_error(error: CryptoError) -> Bool
Check if an error is permanent.
Permanent errors indicate a fundamental problem that will not be resolved by retrying. These require intervention (e.g., re-handshake, configuration fix, or aborting the operation).
Permanent Errors
InvalidSignature- Cryptographic verification failedKeyMismatch- Keys don’t match expected valuesDecryptionFailed- Ciphertext corrupted or wrong keyInitFailed- Provider couldn’t initialize
Example
case crypto.decrypt(ctx, data) {
Error(err) if types.is_permanent_error(err) ->
// Don't retry, re-establish connection
reconnect_and_rehandshake(node)
Error(err) -> retry(fn() { crypto.decrypt(ctx, data) })
Ok(plaintext) -> Ok(plaintext)
}
pub fn is_transient_error(error: CryptoError) -> Bool
Check if an error is transient.
Transient errors are temporary and the operation may succeed if retried with appropriate backoff. Use this to implement retry logic.
Transient Errors
TransientNetwork- Temporary network issuesTimeout- Operation timed out (may succeed later)
Example
case crypto.encrypt(ctx, data) {
Error(err) if types.is_transient_error(err) ->
retry_with_backoff(fn() { crypto.encrypt(ctx, data) })
Error(err) -> Error(err)
Ok(ciphertext) -> Ok(ciphertext)
}
pub fn new_handle(
id: String,
state: dynamic.Dynamic,
) -> ProviderHandle
Create a new provider handle.
Creates an opaque handle that wraps provider state for safe passing between crypto operations. The state is stored as Dynamic to allow provider-specific implementations.
Arguments
id- Unique identifier for this provider instancestate- Provider-specific internal state (typically actor subject)
Returns
An opaque ProviderHandle for use with crypto operations.
pub fn new_handshake_state(
local_node: String,
remote_node: String,
stage: HandshakeStage,
data: dynamic.Dynamic,
) -> HandshakeState
Create a new handshake state.
Constructs intermediate state for tracking an in-progress handshake.
This state is passed between handshake_start and handshake_continue
calls during key exchange.
Arguments
local_node- Identifier of the local noderemote_node- Identifier of the remote node being connected tostage- Current stage in the handshake state machinedata- Provider-specific handshake data (e.g., ephemeral keys)
Example
let state = types.new_handshake_state(
"node_a@localhost",
"node_b@localhost",
KeyExchangeInProgress,
wrap_pending_data(pending),
)
pub fn new_secure_context(
node_id: String,
stage: HandshakeStage,
created_at_ms: Int,
key_id: String,
key_material: dynamic.Dynamic,
) -> SecureContext
Create a new secure context (provider internal use only).
Constructs a SecureContext containing all cryptographic material
needed for encrypt/decrypt operations with a specific remote node.
Arguments
node_id- Identifier of the remote node this context is forstage- Current handshake stage (should beSecureEstablished)created_at_ms- Creation timestamp in millisecondskey_id- Unique identifier for the current key (for logging)key_material- Opaque key material (provider-specific)
Security Note
This function is for provider implementations only. The key_material
parameter contains sensitive cryptographic keys and must never be
logged or serialized.