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

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

  • NotInitialized

    Provider not initialized

  • InitFailed(reason: String)

    Initialization failed

  • ShutdownFailed(reason: String)

    Shutdown failed

  • TransientNetwork(reason: String)

    Transient network error

  • InvalidSignature

    Invalid signature

  • KeyMismatch

    Key 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

Handshake state machine stages.

pub type HandshakeStage {
  Plain
  KeyExchangeInProgress
  SecureEstablished
  Rekeying
  Failed(reason: String)
}

Constructors

  • Plain

    No secure context established

  • KeyExchangeInProgress

    Key exchange in progress

  • SecureEstablished

    Secure context established

  • Rekeying

    Rekeying 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

  • Up

    Provider is fully operational

  • Degraded(reason: String)

    Provider is degraded

  • Down(reason: String)

    Provider is down

Node identifier.

pub type NodeId =
  String

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 established
  • KeyExchangeInProgress - Handshake ongoing
  • SecureEstablished - Ready for encryption
  • Rekeying - Key rotation in progress
  • Failed(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 needed
  • SecureEstablished - Handshake complete
  • Failed(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 failed
  • KeyMismatch - Keys don’t match expected values
  • DecryptionFailed - Ciphertext corrupted or wrong key
  • InitFailed - 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 issues
  • Timeout - 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 instance
  • state - 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 node
  • remote_node - Identifier of the remote node being connected to
  • stage - Current stage in the handshake state machine
  • data - 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 for
  • stage - Current handshake stage (should be SecureEstablished)
  • created_at_ms - Creation timestamp in milliseconds
  • key_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.

Search Document