distribute/crypto/behaviour

Crypto provider behaviour contract for secure communications.

This module defines the contract that crypto providers must implement to provide encryption, key exchange, and secure context management in the distribute library.

Design Philosophy

This behaviour follows distribute’s patterns:

Implementation Approaches

Providers can be implemented as:

  1. No-op provider: Identity transformation for development (insecure!)
  2. AEAD provider: AES-GCM or ChaCha20-Poly1305
  3. ECDH provider: Elliptic curve key exchange + symmetric encryption

State Machine

Key exchange follows a state machine:

Plain -> KeyExchangeInProgress -> SecureEstablished
                                        |
                                        v
                                     Rekeying
                                        |
                                        v
                                 SecureEstablished

Failed states can occur at any transition.

Security Considerations

Example Implementation

See distribute/crypto/noop_adapter for a reference implementation.

Types

Errors from crypto operations.

Classification

  • Transient (retryable): TransientNetwork, Timeout
  • Permanent (do not retry): InvalidSignature, KeyMismatch, DecryptionFailed
pub type CryptoError {
  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

  • InitFailed(reason: String)

    Provider initialization failed

  • ShutdownFailed(reason: String)

    Provider shutdown failed

  • TransientNetwork(reason: String)

    Transient network error during key exchange

  • InvalidSignature

    Invalid cryptographic signature

  • KeyMismatch

    Key mismatch during verification

  • DecryptionFailed(reason: String)

    Decryption failed (invalid ciphertext or wrong key)

  • EncryptionFailed(reason: String)

    Encryption failed

  • NoSecureContext(node: String)

    No secure context for node

  • HandshakeFailed(reason: String)

    Handshake failed

  • RekeyFailed(reason: String)

    Rekey operation 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,
    )

    Arguments

    handshakes_initiated

    Total handshakes initiated

    handshakes_completed

    Total handshakes completed successfully

    handshakes_failed

    Total handshakes failed

    encrypt_count

    Total encrypt operations

    decrypt_count

    Total decrypt operations

    rekey_count

    Total rekey operations

    active_contexts

    Active secure contexts

Messages exchanged during handshake.

The format is provider-specific but typically includes:

  • Public keys or key shares
  • Nonces and session identifiers
  • Signatures for authentication
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)),
    )

    Arguments

    message_type

    Message type identifier

    payload

    Binary payload

    metadata

    Optional metadata

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.

Represents the current state of key exchange with a remote node.

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

Constructors

  • Plain

    No secure context established yet

  • KeyExchangeInProgress

    Key exchange is in progress

  • SecureEstablished

    Secure context successfully established

  • Rekeying

    Rekeying in progress (rotating keys)

  • Failed(reason: String)

    Handshake failed

Handshake state during key exchange.

This opaque type holds the intermediate state during handshake and is passed between handshake_start and handshake_continue calls.

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 operational but degraded

  • Down(reason: String)

    Provider is down

Node identifier for crypto operations.

pub type NodeId =
  String

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),
    )

    Arguments

    name

    Registered name for the provider process

    is_development

    Whether this is a development/insecure provider

    key_rotation_interval_ms

    Key rotation interval in milliseconds (0 = no auto-rotation)

    handshake_timeout_ms

    Handshake timeout in milliseconds

    custom

    Provider-specific custom options

Opaque secure context for a node connection.

Contains the cryptographic material needed for encrypt/decrypt operations. The internal structure is provider-specific and should never be logged or serialized.

pub opaque type SecureContext

Values

pub fn context_key_id(ctx: SecureContext) -> String

Get the key ID from a secure context.

Returns a unique identifier for the current encryption key. Safe to log for debugging; changes after each rekey operation.

pub fn context_node_id(ctx: SecureContext) -> String

Get the node ID from a secure context.

Returns the identifier of the remote node this secure context was established with during handshake.

pub fn context_stage(ctx: SecureContext) -> HandshakeStage

Get the handshake stage from a secure context.

Returns the current state of the security handshake. Should be SecureEstablished before using the context for encryption.

pub fn default_options(name: String) -> ProviderOptions

Default provider options.

pub fn handshake_remote_node(state: HandshakeState) -> String

Get the remote node from handshake state.

Returns the identifier of the remote node this handshake is being conducted with.

pub fn handshake_stage(state: HandshakeState) -> HandshakeStage

Get the stage from handshake state.

Returns the current stage of the handshake process. Use to determine if the handshake needs more message exchanges or has completed.

pub fn is_permanent_error(error: CryptoError) -> Bool

Check if an error is permanent and should not be retried.

Returns True for errors that indicate a fundamental problem that won’t be resolved by retrying (e.g., authentication failure).

pub fn is_transient_error(error: CryptoError) -> Bool

Check if an error is transient and should be retried.

Returns True for errors that are temporary and may succeed on retry (e.g., network issues, timeouts).

pub fn new_handshake_state(
  local_node: String,
  remote_node: String,
  stage: HandshakeStage,
) -> HandshakeState

Create a new handshake state (for provider implementations).

Constructs intermediate state for tracking an in-progress handshake. Used internally by providers to maintain state between handshake steps.

Arguments

  • local_node - Local node identifier
  • remote_node - Remote node identifier
  • stage - Current handshake stage
pub fn new_secure_context(
  node_id: String,
  stage: HandshakeStage,
  created_at_ms: Int,
  key_id: String,
) -> SecureContext

Create a new secure context (for provider implementations).

Constructs a SecureContext for storing encrypted session state. This is a simpler version that doesn’t include key material - use types.new_secure_context for full context with key material.

Arguments

  • node_id - Remote node this context is for
  • stage - Current handshake stage
  • created_at_ms - Creation timestamp
  • key_id - Unique key identifier (safe to log)

Note

This is primarily for the behaviour module’s internal use. Most providers should use types.new_secure_context instead.

Search Document