Chio/Docs
LOGIN · JOIN

Federation Authority

Run the issuing authority for one boundary and hand a partner's verifier a bundle it can check every lease against.

Concept chio@5f63e6e

On this page

The issuing authority for a federation boundary declares its signers in a profile and binds a local seed to each declared key. From one request it signs a capability lease for every workflow step and a governance receipt for every destructive one, and a partner's verifier checks all of it against one trust bundle.

The running example is the authority program from the federation guide project. It issues a lease for the read_refund_case step on did:chio:vendor-a and a destructive stage_refund lease for did:chio:vendor-b, publishes a revocation checkpoint, and assembles the bundle.

Every artifact a verifier reads traces back to three inputs

The profile, the seeds, and the request go in. Leases, a governance receipt, a checkpoint, and the trust bundle come out.

What the authority signsChoose an outcome.
issuing operatorpartnerdeclaresderives keystepsπprofileσsigning seedsrissuance requestκauthorityℓ2 capability leasesscope digests boundρ1 governance receiptccheckpointepoch 10 to 11Ppeer pinsβtrust bundlevverifierbundle parses under the strict verifierissuing operatorpartnerπprofileσsigning seedsrrequestκauthorityℓ2 leasesscope digestsρgovernancereceiptccheckpointepoch 10 to 11Ppeer pinsβtrust bundlevverifierbundle parses under the strict verifier

Every artifact is signed, and the bundle assembles

The authority signs two capability leases, each carrying its scope binding's digest, and one governance receipt for the destructive step. The revocation authority publishes a checkpoint at epoch 11 over epoch 10, and five inputs assemble a trust bundle that parses under the strict verifier. The worked run.

The authority example's artifacts: what the authority signs from the profile, its seeds, and the request, and the five inputs that assemble the verifier trust bundle. The three refusals are the run's. The profile's own path into the bundle, the workflow intersection, and the disclosure policy are left out of the drawing.

Each refusal stops at the artifact it would have produced. A wrong seed signs nothing at all, while a stalled checkpoint leaves the leases already issued intact. The bundle assembles only from complete inputs, so a verifier reads whole bundles.

The profile declares every authority the boundary trusts

An AuthorityProfileDocument names three kinds of signer: lease authorities, governance authorities, and one revocation authority. Each carries a public key, a validity window, and a status. The profile also lists the BBS issuers the verifier accepts and the runtime policy issuer keys.

Validation refuses a key id that mismatches its public key, and a runtime policy issuer key that overlaps an authority key. An authority whose status is inactive is refused at the moment it is asked to sign. A lease authority signs only the action classes in its allowedActionClasses, and a governance authority only the case kinds in its allowedCaseKinds.

Read more in the profile fields.

A seed signs only for the key its authority declares

Seeds live in a separate LocalAuthoritySigningKeysDocument, which a deployment keeps out of every fixture. A lease seed's id is its lease authority's issuer, and a governance seed's id is that authority's authorizingKernel. Before signing, the issuer derives the seed's public key and compares it with the key the profile declares for that authority.

The comparison is what makes the profile binding. A seed swapped for another derives a different key, and issuance stops before a single lease exists, with SigningKeys as the refusal.

One request yields a lease per step and a governance receipt per destructive step

A ChioIssuanceRequest names the workflow and its grant, the profile entries that sign, the verification context, and one entry per step. Each step names its lease, subject, peer kernel, action class, and the digest of its bound arguments. The example program writes its inputs to authority-inputs/, issues from them, and then tries three bad inputs.

Issue, checkpoint, and assemble a verifier trust bundle

Build an authority profile and signing keys, issue two leases and a governance receipt, publish a revocation checkpoint, assemble a strict verifier trust bundle, and refuse a wrong seed, a stalled epoch, and an incomplete pin set.

Complete the project setup, then run the program from federation-guide/. The download includes every constructor and input.

Terminalbash
cargo run --locked --bin authority
Output on darwin/arm64 · exit 0
issued 2 capability leases, 2 lease-scope bindings, 1 governance receipt for the destructive step
seed that does not derive the declared lease authority key: refused (local signing keys failed: lease authority did:chio:buyer-kernel signing seed does not match authority public key)
published revocation checkpoint at epoch 11 over previous epoch 10
checkpoint whose epoch does not advance: refused (revocation checkpoint publication failed: revocation checkpoint epoch must be monotonic)
assembled a verifier trust bundle that parses under the strict verifier
peer pins without the workflow grant class: refused (trust bundle assembly failed: trust bundle action classes must include workflow.grant_issue)

Profile, seeds, and peer pins are deterministic demonstration inputs written to authority-inputs/. A deployment keeps signing seeds out of every fixture, uses its own validity windows, and pins the peers it has actually handshaken with.

Read the complete program 281 lines · complete file
src/bin/authority.rsrust
//! Act as the issuing authority for one boundary: issue leases and a governance
//! receipt, publish a revocation checkpoint, assemble a verifier trust bundle,
//! and show the refusals that keep a wrong key, a stalled epoch, and an
//! incomplete pin set out.
use chio_attest_buyer_core::claims::{
    PeerLadderBinding, VendorKeyBinding, WorkflowIntersectionArtifact,
    WORKFLOW_INTERSECTION_SCHEMA,
};
use chio_attest_buyer_core::context::{ChioVerificationContext, VERIFICATION_CONTEXT_SCHEMA};
use chio_attest_buyer_core::disclosure::ChioDisclosurePolicy;
use chio_attest_buyer_core::issuer::TrustedBbsIssuer;
use chio_attest_buyer_core::trust_bundle::{
    ChioActionClassKind, ChioAuthorityStatus, ChioTrustedActionClass,
    ChioTrustedGovernanceAuthority, ChioTrustedLeaseAuthority, ChioVerifierTrustBundle,
    WORKFLOW_AGGREGATE_PUBLISH_ACTION_CLASS_ID, WORKFLOW_GRANT_ISSUE_ACTION_CLASS_ID,
};
use chio_core_types::crypto::{Keypair, PublicKey};
use chio_federation::bilateral_dsse::Keyid;
use chio_federation::trust_establishment::LadderManifestRef;
use chio_federation_authority::{
    assemble_verifier_trust_bundle, authority_profile_json, issuance_bundle_json,
    issuance_request_json, issue_authority_bundle, peer_pins_json,
    publish_revocation_checkpoint, revocation_publication_request_json,
    signed_revocation_checkpoint_json, signing_keys_json, AuthorityProfileDocument,
    ChioIssuanceRequest, ChioIssuanceStepRequest, ChioRevocationAuthority,
    LocalAuthoritySigningKeysDocument, NamedSeedHex, PeerPinsDocument,
    RevocationPublicationRequest, AUTHORITY_PROFILE_SCHEMA, ISSUANCE_REQUEST_SCHEMA,
    LOCAL_SIGNING_KEYS_SCHEMA, PEER_PINS_SCHEMA, REVOCATION_PUBLICATION_REQUEST_SCHEMA,
};
use chio_governance::authorization::GovernanceReceiptCaseKind;
use chio_governance::lease::CapabilityLeaseActionClass;

const NOW: u64 = 1_766_000_000_000;

fn key(seed: u8) -> Keypair {
    Keypair::from_seed(&[seed; 32])
}
fn key_id(public_key: &PublicKey) -> String {
    Keyid::from_public_key(public_key).0
}

fn profile() -> AuthorityProfileDocument {
    let lease_key = key(11);
    let governance_key = key(12);
    let revocation_key = key(13);
    let runtime_policy_issuer_key = key(42);
    AuthorityProfileDocument {
        schema: AUTHORITY_PROFILE_SCHEMA.to_string(),
        trusted_bbs_issuers: vec![TrustedBbsIssuer {
            issuer_fingerprint: "a".repeat(64),
            public_key_hex: "b".repeat(96),
        }],
        lease_authorities: vec![ChioTrustedLeaseAuthority {
            issuer: "did:chio:buyer-kernel".to_string(),
            key_id: Some(key_id(&lease_key.public_key())),
            public_key: lease_key.public_key(),
            valid_from_unix_ms: Some(NOW - 60_000),
            valid_until_unix_ms: Some(NOW + 60_000),
            status: Some(ChioAuthorityStatus::Active),
            allowed_action_classes: vec![
                CapabilityLeaseActionClass::DelegatedAction,
                CapabilityLeaseActionClass::NarrowDestructive,
            ],
        }],
        governance_authorities: vec![ChioTrustedGovernanceAuthority {
            authorizing_kernel: "did:chio:buyer-governance".to_string(),
            key_id: Some(key_id(&governance_key.public_key())),
            public_key: governance_key.public_key(),
            valid_from_unix_ms: Some(NOW - 60_000),
            valid_until_unix_ms: Some(NOW + 60_000),
            status: Some(ChioAuthorityStatus::Active),
            allowed_case_kinds: vec![GovernanceReceiptCaseKind::DestructiveAuthorization],
        }],
        runtime_policy_issuer_public_keys: vec![runtime_policy_issuer_key.public_key()],
        revocation_authority: ChioRevocationAuthority {
            authority_id: "did:chio:buyer-kernel".to_string(),
            key_id: key_id(&revocation_key.public_key()),
            public_key: revocation_key.public_key(),
            valid_from_unix_ms: NOW - 60_000,
            valid_until_unix_ms: NOW + 60_000,
            status: ChioAuthorityStatus::Active,
        },
    }
}

fn signing_keys() -> LocalAuthoritySigningKeysDocument {
    LocalAuthoritySigningKeysDocument {
        schema: LOCAL_SIGNING_KEYS_SCHEMA.to_string(),
        lease_authority_seeds: vec![NamedSeedHex {
            id: "did:chio:buyer-kernel".to_string(),
            seed_hex: hex::encode([11u8; 32]),
        }],
        governance_authority_seeds: vec![NamedSeedHex {
            id: "did:chio:buyer-governance".to_string(),
            seed_hex: hex::encode([12u8; 32]),
        }],
        revocation_authority_seed_hex: hex::encode([13u8; 32]),
    }
}

fn request() -> ChioIssuanceRequest {
    ChioIssuanceRequest {
        schema: ISSUANCE_REQUEST_SCHEMA.to_string(),
        workflow_id: "wf-001".to_string(),
        workflow_grant_id: "cap-workflow".to_string(),
        lease_authority_issuer: "did:chio:buyer-kernel".to_string(),
        governance_authority_kernel: "did:chio:buyer-governance".to_string(),
        verification_context: ChioVerificationContext {
            schema: VERIFICATION_CONTEXT_SCHEMA.to_string(),
            audience: "buyer-auditor".to_string(),
            challenge: "challenge-001".to_string(),
            proof_purpose: "workflow-disclosure".to_string(),
            issued_at_unix_ms: NOW - 1_000,
            expires_at_unix_ms: NOW + 30_000,
        },
        steps: vec![
            ChioIssuanceStepRequest {
                lease_id: "lease-read".to_string(),
                step_index: 0,
                tool_name: "read_refund_case".to_string(),
                peer_kernel_id: "did:chio:vendor-a".to_string(),
                action_class_id: "read_refund_case".to_string(),
                subject: "did:chio:vendor-a".to_string(),
                action_class: CapabilityLeaseActionClass::DelegatedAction,
                tool_args_hash: "c".repeat(64),
                destructive: false,
                lease_issued_at_unix_ms: NOW - 5_000,
                lease_expires_at_unix_ms: NOW + 20_000,
                governance_receipt_id: None,
                governance_issued_at_unix_ms: None,
                governance_expires_at_unix_ms: None,
                step_sha256: None,
            },
            ChioIssuanceStepRequest {
                lease_id: "lease-stage-refund".to_string(),
                step_index: 1,
                tool_name: "stage_refund".to_string(),
                peer_kernel_id: "did:chio:vendor-b".to_string(),
                action_class_id: "stage_refund".to_string(),
                subject: "did:chio:vendor-b".to_string(),
                action_class: CapabilityLeaseActionClass::NarrowDestructive,
                tool_args_hash: "d".repeat(64),
                destructive: true,
                lease_issued_at_unix_ms: NOW - 5_000,
                lease_expires_at_unix_ms: NOW + 20_000,
                governance_receipt_id: Some("gov-stage-refund".to_string()),
                governance_issued_at_unix_ms: Some(NOW - 4_000),
                governance_expires_at_unix_ms: Some(NOW + 10_000),
                step_sha256: Some("e".repeat(64)),
            },
        ],
    }
}

fn peer_pins() -> PeerPinsDocument {
    PeerPinsDocument {
        schema: PEER_PINS_SCHEMA.to_string(),
        peers: vec![PeerLadderBinding {
            kernel_id: "did:chio:vendor-a".to_string(),
            public_key: key(21).public_key(),
            ladder_manifest_ref: LadderManifestRef {
                manifest_id: "ladder:vendor-a".to_string(),
                sha256: "f".repeat(64),
                issued_at_unix_ms: NOW - 1_000,
                expires_at_unix_ms: NOW + 60_000,
            },
        }],
        vendors: vec![VendorKeyBinding {
            vendor_id: "vendor-a".to_string(),
            public_key: key(21).public_key(),
        }],
        action_classes: vec![
            ChioTrustedActionClass {
                action_class_id: WORKFLOW_GRANT_ISSUE_ACTION_CLASS_ID.to_string(),
                tool_name: WORKFLOW_GRANT_ISSUE_ACTION_CLASS_ID.to_string(),
                kind: ChioActionClassKind::Routine,
            },
            ChioTrustedActionClass {
                action_class_id: WORKFLOW_AGGREGATE_PUBLISH_ACTION_CLASS_ID.to_string(),
                tool_name: WORKFLOW_AGGREGATE_PUBLISH_ACTION_CLASS_ID.to_string(),
                kind: ChioActionClassKind::Routine,
            },
        ],
    }
}

fn checkpoint_request(epoch_height: u64, previous_epoch_height: Option<u64>) -> RevocationPublicationRequest {
    RevocationPublicationRequest {
        schema: REVOCATION_PUBLICATION_REQUEST_SCHEMA.to_string(),
        checkpoint_id: "checkpoint-001".to_string(),
        issued_at_unix_ms: NOW,
        expires_at_unix_ms: NOW + 60_000,
        epoch_height,
        previous_epoch_height,
        revoked_key_fingerprints: Vec::new(),
    }
}

fn workflow_intersection() -> WorkflowIntersectionArtifact {
    WorkflowIntersectionArtifact {
        schema: WORKFLOW_INTERSECTION_SCHEMA.to_string(),
        intersection_id: "workflow-intersection:001".to_string(),
        workflow_id: "wf-001".to_string(),
        workflow_grant_id: "cap-workflow".to_string(),
        pairwise_intersection_refs: Vec::new(),
        step_class_bindings: Vec::new(),
        required_vendor_signers: Vec::new(),
        aggregate_workflow_receipt_sha256: "a".repeat(64),
    }
}

fn disclosure_policy() -> ChioDisclosurePolicy {
    ChioDisclosurePolicy {
        projection_version: "chio.bbs-projection.workflow.v1".to_string(),
        ciphersuite: "BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_".to_string(),
        message_count: 14,
        required_disclosed_indices: vec![4, 8, 9, 10],
        required_disclosed_fields: vec![
            "id".to_string(),
            "session_id".to_string(),
            "skill_id".to_string(),
            "skill_version".to_string(),
        ],
    }
}

fn save(name: &str, json: String) -> std::io::Result<()> {
    std::fs::write(format!("authority-inputs/{name}"), json)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    std::fs::create_dir("authority-inputs")?;
    let profile = profile();
    let keys = signing_keys();
    let request = request();
    let pins = peer_pins();
    save("profile.json", authority_profile_json(&profile)?)?;
    save("request.json", issuance_request_json(&request)?)?;
    // Demonstration seeds only. A deployment keeps this file outside every fixture.
    save("signing-keys.json", signing_keys_json(&keys)?)?;
    save("peer-pins.json", peer_pins_json(&pins)?)?;

    let bundle = issue_authority_bundle(&profile, &request, &keys)?;
    assert_eq!(bundle.capability_leases.len(), 2);
    assert_eq!(bundle.lease_scope_bindings.len(), 2);
    assert_eq!(bundle.governance_receipts.len(), 1);
    save("issuance-bundle.json", issuance_bundle_json(&bundle)?)?;
    println!("issued 2 capability leases, 2 lease-scope bindings, 1 governance receipt for the destructive step");

    let mut wrong = signing_keys();
    wrong.lease_authority_seeds[0].seed_hex = hex::encode([99u8; 32]);
    let err = issue_authority_bundle(&profile, &request, &wrong).unwrap_err();
    println!("seed that does not derive the declared lease authority key: refused ({err})");

    let advance = checkpoint_request(11, Some(10));
    save("revocations.json", revocation_publication_request_json(&advance)?)?;
    let checkpoint = publish_revocation_checkpoint(&profile, &advance, &keys)?;
    save("checkpoint.json", signed_revocation_checkpoint_json(&checkpoint)?)?;
    println!("published revocation checkpoint at epoch 11 over previous epoch 10");

    let stalled = checkpoint_request(10, Some(10));
    save("revocations-stalled.json", revocation_publication_request_json(&stalled)?)?;
    let err = publish_revocation_checkpoint(&profile, &stalled, &keys).unwrap_err();
    assert!(err.to_string().contains("monotonic"));
    println!("checkpoint whose epoch does not advance: refused ({err})");

    let intersection = workflow_intersection();
    save("workflow-intersection.json", serde_json::to_string_pretty(&intersection)?)?;
    save("disclosure-policy.json", serde_json::to_string_pretty(&disclosure_policy())?)?;
    let document = assemble_verifier_trust_bundle(&profile, &pins, &intersection, disclosure_policy(), checkpoint)?;
    save("trust-bundle.json", serde_json::to_string_pretty(&document)?)?;
    ChioVerifierTrustBundle::from_document(document)?;
    println!("assembled a verifier trust bundle that parses under the strict verifier");

    let mut missing = peer_pins();
    missing.action_classes.retain(|class| class.action_class_id != WORKFLOW_GRANT_ISSUE_ACTION_CLASS_ID);
    let checkpoint = publish_revocation_checkpoint(&profile, &advance, &keys)?;
    let err = assemble_verifier_trust_bundle(&profile, &missing, &intersection, disclosure_policy(), checkpoint).unwrap_err();
    println!("peer pins without the workflow grant class: refused ({err})");
    Ok(())
}

Open the source file. Each program asserts its expected refusals; keys, timestamps, and digests change between runs.

You should see two leases, two scope bindings, and one governance receipt for the refund step, then a checkpoint at epoch 11 over epoch 10 and a bundle that parses under the strict verifier. The three refusals are a seed for did:chio:buyer-kernel that derives the wrong key, a checkpoint at epoch 10 over epoch 10, and peer pins without the workflow.grant_issue action class.

The CLI issues the same bundle from those input files:

Issue the bundle with the CLI from the same inputs

Terminalbash
chio federation authority issue --profile authority-inputs/profile.json --request authority-inputs/request.json --signing-keys authority-inputs/signing-keys.json --out-dir authority-inputs/cli-bundle
ls authority-inputs/cli-bundle
Output · exit 0
capability-leases.json
governance-receipts.json
issuance-bundle.json
lease-scope-bindings.json
verification-context.json

You should see the five files of one ChioIssuanceBundle. Every step gets a signed lease and a scope binding whose digest the lease carries. A step marked destructive must name a governance receipt and carry a lowercase SHA-256 stepSha256, and the bundle holds one signed receipt for it. The action classes are scoped_observation, delegated_action, and narrow_destructive.

Read more in Capability Leases.

Each refusal names the document that failed

The issuer returns one error variant per stage, so the variant tells you which file to fix.

  • Profile: the profile fails validation.
  • Request: the request fails validation.
  • SigningKeys: a seed does not derive the declared key.
  • Issuance: an authority cannot sign. It is missing from the profile or inactive, has no usable validity window, or lacks the destructive authorization or action class the request needs; or a lease, receipt, or checkpoint window falls outside the authority window.
  • Revocation: the checkpoint epoch does not advance, or the revocation authority is inactive.
  • TrustBundle: the pin set lacks a reference workflow class, or the assembled bundle or the peer pins fail strict validation.
  • Json: a document is not valid JSON. Canonical: the workflow intersection could not be canonicalized (RFC 8785) for hashing.

Every variant is indexed with its repair on Federation Refusal Codes.

Authority documents

Five JSON documents carry the authority. The issuer is crates/trust/chio-federation-authority, with profile validation in src/profile.rs; lease semantics are in crates/trust/chio-governance/src/lease.rs.

AuthorityProfileDocument

  • schema: chio.federation.authority-profile.v1.
  • trustedBbsIssuers[]: issuerFingerprint and publicKeyHex of each BBS issuer the verifier accepts.
  • leaseAuthorities[]: issuer, keyId, publicKey, validFromUnixMs, validUntilUnixMs, status, allowedActionClasses.
  • governanceAuthorities[]: authorizingKernel, keyId, publicKey, validFromUnixMs, validUntilUnixMs, status, allowedCaseKinds.
  • runtimePolicyIssuerPublicKeys[]: the runtime policy issuer roots. None may overlap an authority key.
  • revocationAuthority: authorityId, keyId, publicKey, validFromUnixMs, validUntilUnixMs, status.

LocalAuthoritySigningKeysDocument

  • schema: chio.federation.local-signing-keys.v1.
  • leaseAuthoritySeeds[]: id (the lease authority's issuer) and seedHex. The seed signs only if its public key equals that authority's declared key.
  • governanceAuthoritySeeds[]: id (the governance authority's authorizingKernel) and seedHex, under the same rule.
  • revocationAuthoritySeedHex: the revocation authority's seed.

ChioIssuanceRequest

  • schema: chio.federation.issuance-request.v1.
  • workflowId, workflowGrantId: the workflow and its grant.
  • leaseAuthorityIssuer, governanceAuthorityKernel: which profile entries sign.
  • verificationContext: audience, challenge, proofPurpose, and the window.
  • steps[]: one ChioIssuanceStepRequest per workflow step.

ChioIssuanceStepRequest

  • leaseId, stepIndex, toolName: the lease and the step it covers.
  • peerKernelId, subject: who the lease is for.
  • actionClassId, actionClass: the class name and its kind, one of scoped_observation, delegated_action, narrow_destructive.
  • toolArgsHash: the digest of the bound arguments.
  • destructive: a destructive step must name a governance receipt.
  • leaseIssuedAtUnixMs, leaseExpiresAtUnixMs: the lease window.
  • governanceReceiptId, governanceIssuedAtUnixMs, governanceExpiresAtUnixMs: the governance receipt for a destructive step.
  • stepSha256: the lowercase SHA-256 step digest. Required on a destructive step and refused on any other step.

ChioIssuanceBundle

  • schema: chio.federation.issuance-bundle.v1.
  • capabilityLeases[]: one signed lease per step.
  • leaseScopeBindings[]: one scope binding per step, whose digest its lease carries.
  • governanceReceipts[]: one signed receipt per destructive step.
  • verificationContext: the request's context, carried through.

Verifier trust bundle inputs

The bundle a verifier reads assembles from five inputs: the authority profile, the peer pins, the workflow intersection, the disclosure policy, and a signed revocation checkpoint. The pins must include the workflow.grant_issue action class. The bundle and the pins both pass strict validation before assembly returns.

Next: publish the checkpoints a verifier reads

Federation Authority · Chio Docs