confium-composite — composite signatures

Composite multi-algorithm signatures for post-quantum migration. A single composite signature contains the artifacts of multiple component algorithms (e.g. Ed25519 + ECDSA-P256 + ML-DSA-65); verifiers check all components and accept the signature only if every component verifies.

When to use this crate

Use confium-composite when:

  • You are migrating from a classical algorithm (Ed25519, ECDSA) to a post-quantum one (ML-DSA, SLH-DSA) and need both to verify simultaneously during the transition.
  • You want defense-in-depth: a break in any single algorithm does not compromise the composite signature.
  • You are building a transparency log leaf hash or a certificate signature that must remain verifiable across the PQ transition.

Public API

The crate exposes a CompositeSignature value type. Verification takes a closure that dispatches per component — you supply the verifier for each algorithm the composite contains.

use confium_composite::{CompositeSignature, ed25519_verifier, ED25519};

let composite: CompositeSignature = /* ... */;
let result = composite.verify(&message, |alg, pk, msg, sig| {
    if alg == ED25519 {
        ed25519_verifier(alg, pk, msg, sig)
    } else {
        // Route other algorithms to their verifiers.
        Err(format!("no verifier for \{alg\}"))
    }
})?;

// result.all_verified — true iff every component verified
// result.per_component — Vec<ComponentResult> with per-algorithm detail

Built-in verifiers ship for Ed25519 (ed25519_verifier) and ECDSA-P256 (p256_verifier). Route other algorithms through your own backend (Botan plugin, OpenSSL provider) inside the closure.

Verification semantics

A composite signature is valid if and only if:

  1. Every component signature verifies against the message.
  2. Every required component algorithm is registered with the verifier.
  3. The component set matches the deployment’s policy (e.g. the jurisdictional policy may require ≥1 classical + ≥1 PQ algorithm).

A missing verifier for any component is a hard failure, not a soft-accept. Include every algorithm the deployment expects to encounter in your verify closure.

Security notes

  • No silent downgrade: if a verifier is missing for a component, verification fails. The crate never silently accepts on the subset of components it can verify.
  • Callback isolation: per-algorithm verification runs as isolated closure invocations. An error in one does not short-circuit the others; each result is collected and AND-reduced at the end.
  • Constant-time where it matters: the per-algorithm verifiers supplied by the caller are responsible for their own constant-time guarantees. The composite layer does not introduce branches that depend on secret data.
  • Order independence: the composite signature lists components in a deterministic order; verification does not depend on the order the per-algorithm verifiers are registered.