basil-cose 0.6.1

Strict deterministic COSE (RFC 9052/9053) profile for basil sealed invocations: signed, sealed, and seal-only constructions with in-place signer/recipient traits
Documentation
// SPDX-FileCopyrightText: 2026 OpenBasil Contributors
//
// SPDX-License-Identifier: Apache-2.0

//! # basil-cose
//!
//! A strict, deterministic COSE (RFC 9052/9053) profile for basil's sealed
//! invocations: broker-free and publishable, shared by the basil broker,
//! the basil client, and some basil clients.
//!
//! Three constructions:
//!
//! - **Signed**: a bare `COSE_Sign1` ([`build_signed`] / [`verify_signed`]).
//! - **Sealed**: a `COSE_Sign1` over an embedded tagged `COSE_Encrypt`
//!   ([`build_sealed`] / [`verify_sealed`], then [`VerifiedSealed::open`]).
//! - **Seal-only**: a bare `COSE_Encrypt` ([`build_encrypted`] /
//!   [`decode_encrypted`], then [`EncryptedMessage::open`]).
//!
//! Algorithms: `EdDSA` (-8) or `ES256` (-7, ECDSA P-256 + SHA-256) signatures,
//! ECDH-ES + HKDF-256 (-25) key agreement with X25519, and A256GCM (3) or
//! `ChaCha20`-`Poly1305` (24) content encryption. Key material stays behind
//! the [`Signer`], [`Verifier`], and [`Recipient`] traits; nonces and
//! ephemerals are always generated by the library. `ES256` signing is
//! deterministic (RFC 6979), so both signature algorithms re-sign
//! byte-identically.
//!
//! ## Strictness
//!
//! Every decode entry point enforces the profile: tagged top-level
//! structures only, definite lengths, RFC 8949 §4.2 deterministic encodings
//! (checked by re-encoding the parsed message and comparing bytes, on every
//! decode, release builds included), closed algorithm/label allow-sets with
//! no `Unknown` arms, `crit` coverage of every profile label, claims only in
//! protected headers, and exactly one recipient.
//!
//! ## Claims
//!
//! Claims ride in the protected header as a CWT map (header 15) plus basil
//! private labels (`-70001..=-70005`, see [`label`]). [`ValidationParams`]
//! parameterizes skew/TTL/audience bounds; `now` is injected, never sampled.
//!
//! The crate is `no_std` + `alloc` and obtains production randomness through
//! `getrandom`.

#![no_std]
#![cfg_attr(
    test,
    allow(clippy::unwrap_used, clippy::indexing_slicing, clippy::panic)
)]
// AFIT is a deliberate design decision (approved design §4.5/§7.1): traits
// are consumed through generics, and local implementations are synchronous.
// Send bounds, when a consumer needs them, are added at the consumer's
// generic bound site, which is also why `future_not_send` is allowed: the
// entry-point futures are generic over unbounded `Signer`/`Verifier`/
// `Recipient` implementations, and imposing `Send` here would forbid
// legitimate single-threaded (e.g. WASM) implementors.
#![allow(async_fn_in_trait)]
#![allow(clippy::future_not_send)]

extern crate alloc;

mod alg;
mod claims;
mod codec;
mod encrypt;
mod error;
mod hash;
mod kdf;
mod keys;
pub mod label;
mod seal;
mod sign;
#[cfg(test)]
mod tests;
mod traits;
mod types;

pub use alg::{ContentAlgorithm, KeyAgreementAlgorithm, SignatureAlgorithm};
pub use claims::{Claims, MessageRole, ProtectedHeaders, ValidationParams};
pub use encrypt::{EncryptParams, EncryptedMessage, Opened, build_encrypted, decode_encrypted};
#[cfg(feature = "fixtures")]
pub use encrypt::{SealParts, build_encrypted_with_parts};
pub use error::{
    BuildError, ClaimsError, DecodeError, OpenError, ProfileError, SignError, VerifyError,
};
pub use hash::{RequestHash, request_hash};
pub use kdf::{KdfParties, PartyIdentity};
pub use keys::{
    Ed25519Signer, Ed25519Verifier, Es256Signer, KeyError, KeyLengthError, P256Verifier,
    X25519Recipient, X25519RecipientPublic,
};
#[cfg(feature = "fixtures")]
pub use seal::build_sealed_with_parts;
pub use seal::{SealParams, VerifiedSealed, VerifySealedParams, build_sealed, verify_sealed};
pub use sign::{
    SignParams, VerifiedSigned, VerifySignedParams, build_signed, build_signed_with_headers,
    verify_signed,
};
pub use traits::{OpenRequest, Recipient, Signer, Verifier};
pub use types::{
    ContentType, CoseBytes, ExternalAad, KeyId, MessageId, ResponseSubject, SealedAad, Signature,
    Subject, UnixTime,
};

// Re-exported so trait implementors and callers name the same zeroizing
// wrapper this crate's APIs use.
pub use zeroize::Zeroizing;