aegis-delegate 0.2.0

AEGIS delegation and authority model — delegation trees, session keys, scope constraints
Documentation

aegis-delegate

Delegation and authority model for AEGIS. Create and verify cryptographic delegation proofs, manage delegation trees with depth limits, issue time-limited session keys, validate scope anti-amplification, and track revocations with cascading.

Delegation Proofs

Create Ed25519-signed delegation proofs using JCS canonicalization. The delegator signs a canonical JSON payload binding the delegate's DID to a specific scope.

use aegis_delegate::proof::{create_delegation_proof, verify_delegation_proof};
use aegis_core::DelegationScope;
use ed25519_dalek::SigningKey;

let scope = DelegationScope {
    actions:   vec!["transfer".into(), "approve".into()],
    resources: vec!["0xtoken_contract".into()],
    chains:    vec!["ethereum".into()],
    limits:    None,
    temporal:  None,
};

let delegation = create_delegation_proof(
    "did:oas:prod:hmr:alice",           // delegator
    "did:oas:prod:agent:bot1",          // delegate
    scope,
    Some(Utc::now() + Duration::days(7)), // expires in 7 days
    &signing_key,
    "did:oas:prod:hmr:alice#delegation-key",
)?;

// Verify the proof
let valid = verify_delegation_proof(&delegation, &verifying_key)?;
assert!(valid);

Functions

/// Create a signed delegation proof.
///
/// Signs a JCS-canonicalized JSON payload containing:
/// delegator DID, delegate DID, scope, and optional expiry.
/// Proof type: "AegisDelegationProof2025"
pub fn create_delegation_proof(
    delegator_did: &str,
    delegate_did: &str,
    scope: DelegationScope,
    expires: Option<DateTime<Utc>>,
    signing_key: &SigningKey,
    verification_method: &str,
) -> Result<Delegation, DelegationError>;

/// Verify a delegation proof against the delegator's public key.
///
/// Re-canonicalizes the payload and verifies the JWS signature.
pub fn verify_delegation_proof(
    delegation: &Delegation,
    delegator_public_key: &VerifyingKey,
) -> Result<bool, DelegationError>;

Scope Validation

Prevent scope amplification: a delegate's scope must be a subset of (or equal to) the delegator's scope.

use aegis_delegate::scope::{check_scope_validity, amplify_scope};

// Ensure a scope is well-formed
check_scope_validity(&scope)?;

// Check that delegate scope does not exceed delegator scope
amplify_scope(&delegator_scope, &delegate_scope)?;
// Returns Ok(()) if valid, Err(ScopeAmplification) if delegate exceeds delegator

Functions

/// Validate that a delegation scope is well-formed.
/// Checks: non-empty actions, valid chain names.
pub fn check_scope_validity(scope: &DelegationScope) -> Result<(), DelegationError>;

/// Check for scope amplification.
/// Returns Err(ScopeAmplification) if delegate_scope contains
/// actions, resources, or chains not present in delegator_scope.
pub fn amplify_scope(
    delegator_scope: &DelegationScope,
    delegate_scope: &DelegationScope,
) -> Result<(), DelegationError>;

Delegation Tree

Track delegations as a directed tree. Enforces maximum depth, provides chain verification, and computes effective scopes by intersecting parent scopes.

use aegis_delegate::tree::DelegationTree;

let mut tree = DelegationTree::new(5); // max depth = 5

tree.add_delegation(&delegation)?;

// Verify the delegation chain for a delegate
let chain_valid = tree.verify_chain("did:oas:prod:agent:bot1")?;

// Get the effective scope (intersection of all parent scopes)
let effective = tree.get_effective_scope("did:oas:prod:agent:bot1")?;

// Get depth of a node in the tree
let depth = tree.get_depth("did:oas:prod:agent:bot1");

// Revoke a delegation (cascading to all children)
let revoked_ids = tree.revoke("delegation-id-123")?;

DelegationTree

impl DelegationTree {
    /// Create a new tree with a maximum delegation depth.
    pub fn new(max_depth: u32) -> Self;

    /// Add a delegation to the tree.
    /// Returns Err(MaxDepthExceeded) if adding would exceed max_depth.
    pub fn add_delegation(&mut self, delegation: &Delegation) -> Result<(), DelegationError>;

    /// Verify the delegation chain from a delegate back to the root delegator.
    pub fn verify_chain(&self, delegate_did: &str) -> Result<bool, DelegationError>;

    /// Compute the effective scope for a delegate by intersecting all parent scopes.
    pub fn get_effective_scope(
        &self,
        delegate_did: &str,
    ) -> Result<DelegationScope, DelegationError>;

    /// Get the depth of a DID in the delegation tree.
    pub fn get_depth(&self, did: &str) -> usize;

    /// Revoke a delegation and cascade to all children.
    /// Returns the list of all revoked delegation IDs.
    pub fn revoke(&mut self, delegation_id: &str) -> Result<Vec<String>, DelegationError>;
}

Session Keys

Issue time-limited session keys with constrained scope and optional transaction limits.

use aegis_delegate::session_key::SessionKeyIssuer;

let session_key = SessionKeyIssuer::issue_session_key(
    "did:oas:prod:hmr:alice",
    scope,
    Some(100),                    // max 100 transactions
    &signing_key,
    "did:oas:prod:hmr:alice#session-key",
)?;

// Verify the session key
let valid = SessionKeyIssuer::verify_session_key(
    &session_key,
    &verifying_key,
)?;
assert!(valid);

SessionKeyIssuer

impl SessionKeyIssuer {
    /// Issue a new session key with scope and optional transaction limit.
    pub fn issue_session_key(
        principal_did: &str,
        scope: DelegationScope,
        max_transactions: Option<u64>,
        signing_key: &SigningKey,
        verification_method: &str,
    ) -> Result<SessionKey, DelegationError>;

    /// Verify a session key's proof against the principal's public key.
    pub fn verify_session_key(
        session_key: &SessionKey,
        principal_public_key: &VerifyingKey,
    ) -> Result<bool, DelegationError>;
}

Storage Traits

DelegationStore

#[async_trait]
pub trait DelegationStore: Send + Sync {
    async fn store(&self, delegation: &Delegation) -> Result<(), DelegationError>;
    async fn load(&self, delegation_id: &str) -> Result<Delegation, DelegationError>;
    async fn list_by_delegator(&self, delegator_did: &str) -> Result<Vec<Delegation>, DelegationError>;
    async fn list_by_delegate(&self, delegate_did: &str) -> Result<Vec<Delegation>, DelegationError>;
    async fn delete(&self, delegation_id: &str) -> Result<(), DelegationError>;
}

RevocationStore

#[async_trait]
pub trait RevocationStore: Send + Sync {
    async fn revoke(&self, delegation_id: &str) -> Result<(), DelegationError>;
    async fn is_revoked(&self, delegation_id: &str) -> Result<bool, DelegationError>;
    async fn list_revoked(&self) -> Result<Vec<String>, DelegationError>;
}

Both have in-memory implementations (InMemoryDelegationStore, InMemoryRevocationStore).

License

Copyright © 2026 L1fe Labs, Inc.

Licensed under either of Apache License 2.0 or MIT license, at your option.