krypteia-arcana 0.1.0

Pure-Rust classical cryptographic primitives: RSA (PKCS#1 v1.5, OAEP), ECC (NIST P-256/384/521, secp256k1), ECDSA, EdDSA (Ed25519), X25519, AES (128/192/256, GCM/CBC), DES/3DES, SHA-1/2/3, HMAC. Side-channel-aware (Montgomery ladder, branchless point_add_ct). Targets embedded (no_std), STM32 M0/M4/M33, ESP32-C3 RISC-V. Zero runtime dependencies.
Documentation
//! # arcana — classical cryptography for the `krypteia` workspace
//!
//! Pure-Rust implementations of widely-used classical primitives —
//! hash functions, symmetric ciphers, AEAD modes, RSA, ECDSA / ECDH,
//! EdDSA, X25519, and X448 — sharing the same side-channel
//! countermeasure toolkit ([`silentops`](https://docs.rs/silentops))
//! used by the post-quantum side of the workspace
//! ([`quantica`](https://docs.rs/quantica)).
//!
//! Zero external runtime dependencies (only `std` / `alloc` and the
//! workspace-local `silentops`); constant-time on the data path.
//!
//! # Algorithms
//!
//! ## Hash functions ([`hash`])
//!
//! | Algorithm    | Output  | Module                                          |
//! |--------------|---------|-------------------------------------------------|
//! | SHA-1        | 160 b   | [`hash::sha1::Sha1`] (legacy)                   |
//! | SHA-224      | 224 b   | [`hash::sha224::Sha224`]                        |
//! | SHA-256      | 256 b   | [`hash::sha256::Sha256`]                        |
//! | SHA-384      | 384 b   | [`hash::sha384::Sha384`]                        |
//! | SHA-512      | 512 b   | [`hash::sha512::Sha512`]                        |
//! | SHA-512/224  | 224 b   | [`hash::sha512_trunc::Sha512_224`]              |
//! | SHA-512/256  | 256 b   | [`hash::sha512_trunc::Sha512_256`]              |
//! | SHA3-224     | 224 b   | [`hash::sha3::Sha3_224`]                        |
//! | SHA3-256     | 256 b   | [`hash::sha3::Sha3_256`]                        |
//! | SHA3-384     | 384 b   | [`hash::sha3::Sha3_384`]                        |
//! | SHA3-512     | 512 b   | [`hash::sha3::Sha3_512`]                        |
//! | SHAKE128     | XOF     | [`hash::sha3::Shake128`]                        |
//! | SHAKE256     | XOF     | [`hash::sha3::Shake256`]                        |
//! | cSHAKE128    | XOF     | [`hash::sha3::CShake128`]                       |
//! | cSHAKE256    | XOF     | [`hash::sha3::CShake256`]                       |
//! | BLAKE2b      | 1-512 b | [`hash::blake2::Blake2b`]                       |
//! | BLAKE2s      | 1-256 b | [`hash::blake2::Blake2s`]                       |
//! | RIPEMD-160   | 160 b   | [`hash::ripemd160::Ripemd160`] (legacy)         |
//!
//! ## Symmetric ciphers and modes ([`cipher`])
//!
//! | Algorithm                         | Module                                       |
//! |-----------------------------------|----------------------------------------------|
//! | AES-128 / 192 / 256               | [`cipher::aes`]                              |
//! | DES, Triple-DES (EDE)             | [`cipher::des`]                              |
//! | ECB, CBC, CTR, GCM modes          | [`cipher::modes`]                            |
//! | **AES-CCM** (RFC 3610) AEAD        | [`cipher::ccm`]                              |
//! | **AES-XTS** (IEEE 1619) disk crypto| [`cipher::xts`]                              |
//! | **ChaCha20** (RFC 8439)           | [`cipher::chacha20`]                         |
//! | **Poly1305** one-time MAC         | [`cipher::poly1305`]                         |
//! | **ChaCha20-Poly1305** AEAD        | [`cipher::chacha20poly1305`]                 |
//! | **XChaCha20-Poly1305** AEAD       | [`cipher::xchacha20poly1305`] (24-byte nonce) |
//!
//! In addition to these one-shot, function-oriented APIs, a
//! stateful **streaming `Cipher` object** lives in
//! [`cipher::ctx`]. It wraps the AES / DES / 3DES block ciphers
//! with the ECB / CBC / CTR modes behind a uniform
//! `init / update / finalize` cycle, with caller-provided output
//! buffers (no allocation required) and configurable padding
//! (`None`, `Pkcs7`, `Iso9797M1`, `Iso9797M2`, `AnsiX923`). AEAD
//! modes intentionally stay function-oriented to avoid releasing
//! unverified plaintext during streaming decryption.
//!
//! ## Message authentication codes ([`mac`])
//!
//! A streaming MAC object lives in [`mac::ctx`], exposing a
//! uniform `init / update / sign | verify` cycle across four
//! families:
//!
//! | Family       | Algorithms                                                       | Standard          |
//! |--------------|------------------------------------------------------------------|-------------------|
//! | HMAC         | SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256/384/512, RIPEMD-160   | RFC 2104, FIPS 198-1 |
//! | CMAC         | AES-128 / 192 / 256, Triple-DES                                  | NIST SP 800-38B, RFC 4493 |
//! | KMAC         | KMAC128, KMAC256                                                 | FIPS SP 800-185   |
//! | GMAC         | AES-128 / 192 / 256                                              | NIST SP 800-38D   |
//!
//! Three init variants distinguish families that need different
//! inputs: `init(key)` (HMAC, CMAC, KMAC default),
//! `init_kmac(key, custom)` (KMAC with explicit customization
//! string), and `init_with_nonce(key, nonce)` (GMAC, 12-byte
//! unique nonce). `verify` accepts truncated tags and runs in
//! constant time. Poly1305 is intentionally **not** routed
//! through `Mac` because it is a one-time MAC and would be unsafe
//! behind an "init then reuse" object.
//!
//! ## RSA ([`rsa`])
//!
//! | Padding                           | Module                                       |
//! |-----------------------------------|----------------------------------------------|
//! | PKCS#1 v1.5 encryption + signature| [`rsa::pkcs1`] (8 hash functions supported)  |
//! | OAEP encryption (PKCS#1 v2.2)     | [`rsa::oaep`]                                |
//! | RSASSA-PSS signature (PKCS#1 v2.2)| [`rsa::pss`]                                 |
//!
//! ## Elliptic curve cryptography ([`ecc`])
//!
//! ECDSA / ECDH / SEC1-compressed / signature DER are all unified
//! behind a single [`ecc::curves::Curve`] trait, implemented by:
//!
//! | Wrapper                                   | Curve              |
//! |-------------------------------------------|--------------------|
//! | [`ecc::curves::P256`]                     | NIST P-256         |
//! | [`ecc::curves::P384`]                     | NIST P-384         |
//! | [`ecc::curves::P521`]                     | NIST P-521         |
//! | [`ecc::curves::Secp256k1`]                | secp256k1 (SECG)   |
//! | [`ecc::curves::BrainpoolP256r1`]          | BSI / RFC 5639     |
//! | [`ecc::curves::BrainpoolP384r1`]          | BSI / RFC 5639     |
//! | [`ecc::curves::BrainpoolP512r1`]          | BSI / RFC 5639     |
//!
//! Edwards / Montgomery curves live in standalone modules because
//! their algebraic shape doesn't fit the short-Weierstrass `Curve`
//! trait:
//!
//! | Algorithm                         | Module                |
//! |-----------------------------------|-----------------------|
//! | Ed25519, Ed25519ctx, Ed25519ph    | [`ecc::eddsa`]        |
//! | X25519 ECDH (Curve25519)           | [`ecc::x25519`]       |
//! | X448 ECDH (Curve448)               | [`ecc::x448`]         |
//!
//! Ed448 is planned but not yet implemented.
//!
//! # Cargo features
//!
//! | Feature              | Default | Effect                                                  |
//! |----------------------|---------|---------------------------------------------------------|
//! | `std`                | no      | Reserved for future `no_std` work (currently a no-op).  |
//! | `rust-crypto-traits` | no      | Pulls in `digest 0.10` / `cipher 0.4` / `signature 2.0` and activates the `bridge` module, which wraps every hash in a `digest::Digest` impl for ecosystem interop (HMAC, HKDF, PBKDF2, Argon2, ...). |
//!
//! Default builds are **zero-dependency** (only the workspace-local
//! `silentops` crate). The `rust-crypto-traits` feature is opt-in
//! and pulls in definitions only (no crypto code).
//!
//! # Quick start
//!
//! ```rust
//! // SHA-256 one-shot hash
//! use arcana::hash::sha256::Sha256;
//! use arcana::Hasher;
//! let digest = Sha256::hash(b"hello, arcana");
//! assert_eq!(digest.len(), 32);
//! ```
//!
//! ```rust
//! // AES-128-GCM AEAD
//! use arcana::cipher::aes::Aes128;
//! use arcana::cipher::modes::Gcm;
//! use arcana::BlockCipher;
//!
//! let key = [0x42u8; 16];
//! let nonce = [0u8; 12];
//! let cipher = Aes128::new(&key);
//! let (ct, tag) = Gcm::encrypt(&cipher, &nonce, b"aad", b"plaintext");
//! let pt = Gcm::decrypt(&cipher, &nonce, b"aad", &ct, &tag).unwrap();
//! assert_eq!(pt, b"plaintext");
//! ```
//!
//! ```rust
//! // X25519 ECDH key exchange
//! use arcana::ecc::x25519::{x25519_derive_public, x25519_ecdh};
//! let alice_sk = [0x77u8; 32];
//! let bob_sk   = [0x88u8; 32];
//! let alice_pk = x25519_derive_public(&alice_sk);
//! let bob_pk   = x25519_derive_public(&bob_sk);
//! let shared_a = x25519_ecdh(&alice_sk, &bob_pk);
//! let shared_b = x25519_ecdh(&bob_sk,   &alice_pk);
//! assert_eq!(shared_a, shared_b);
//! ```
//!
//! # Examples
//!
//! ```sh
//! cargo run -p arcana --release --example hash_demo
//! cargo run -p arcana --release --example aes_demo
//! cargo run -p arcana --release --example rsa_demo
//! cargo run -p arcana --release --example ecdsa_demo
//! cargo run -p arcana --release --example eddsa_demo
//! cargo run -p arcana --release --example x25519_demo
//! ```
//!
//! # Side-channel guarantees
//!
//! The full threat model and per-algorithm countermeasure roadmap
//! lives in `arcana/doc/sca/` (HTML rendered by `./gendoc.sh
//! arcana`). The roadmap items referenced here (`T1-A`, `T1-C`,
//! `T2-D` …) are defined there. This section is a quick-reference
//! summary; for evaluation evidence, refer to the annex.
//!
//! ## Always-on
//!
//! | Defence                            | Scope                                                                                  |
//! |------------------------------------|----------------------------------------------------------------------------------------|
//! | Constant-time tag comparison       | All AEAD decrypt, MAC verify, ECDSA verify (via `silentops::ct_eq`)                    |
//! | Constant-time field arithmetic     | ECC (P-256, P-384, P-521, secp256k1, Brainpool), Ed25519, X25519, X448                 |
//! | **CT Montgomery ladder**           | [`ecc::curve::scalar_mul_point`] — branch-free across all 7 short-Weierstrass curves   |
//! | `core::hint::black_box` shielding  | [`ecc::field`] mask selects, to keep LLVM from recovering branches at `opt-level >= 2` |
//! | No secret-dependent branches       | Hash, symmetric, HMAC, CMAC, KMAC, GMAC                                                |
//! | RFC 6979 deterministic nonce       | ECDSA — eliminates nonce-reuse attacks (but see fault-attack note below)               |
//! | `silentops::ct_zeroize` available  | Caller can zeroize sensitive buffers explicitly                                        |
//!
//! ## Open vulnerabilities (evaluation gaps — track in roadmap)
//!
//! | Primitive           | Issue                                                                | Roadmap item |
//! |---------------------|----------------------------------------------------------------------|--------------|
//! | AES S-box           | Table-based lookup — cache-line leaks on CPUs with shared L1         | `T1-A` (fixsliced AES port from Adomnicai-Peyrin TCHES 2021/1) |
//! | RSA-CRT decrypt     | Bellcore single-fault → factorisation of `N`                         | `T1-C` (Aumüller 2002, formally verified) |
//! | RSA bigint          | `Montgomery_mul`, `cmp`, `pow_mod` not formally CT-audited           | `T1-E` |
//! | ECDSA / ECDH        | Minerva-class bit-length leak audit not yet completed                | `T1-B` |
//! | Ed25519 / ECDSA-RFC 6979 | Single-fault on deterministic signing → key recovery              | `T1-D` (hedged signatures, CFRG draft) |
//! | HMAC-SHA-2          | Carry-based DPA breaks unmasked HMAC-SHA-2 in 30 K – 275 K traces    | `T2-D` (first-order Boolean masking) |
//! | DES / 3DES S-boxes  | Table-based; legacy only                                             | unscoped — avoid on SCA-sensitive targets |
//!
//! ## Not yet implemented
//!
//! - **Zeroize-on-Drop**: typed key wrappers ([`ecc::curves::SecretKey`],
//!   [`ecc::eddsa::Ed25519SecretKey`], [`rsa::rsa::RsaSecretKey`])
//!   currently **do not** implement `Drop` with
//!   `silentops::ct_zeroize`. Callers should zeroize sensitive
//!   buffers explicitly. Roadmap item `T2-E`.
//! - **DPA / EM / multi-fault**: out of scope for the current
//!   evaluation profile; tier-4 items in the SCA annex.
//!
//! # Native API vs RustCrypto bridge
//!
//! By default, this crate exposes its own trait hierarchy
//! ([`Hasher`], [`Xof`], [`BlockCipher`], ...). Enable
//! `rust-crypto-traits` to additionally activate the `bridge`
//! module which implements `digest::Digest` for the hash
//! functions. The two universes are intentionally separate so the
//! native modules never depend on a specific external crate
//! version.

// ============================================================
// Our own trait definitions (zero-dependency)
// ============================================================

/// Trait for hash functions (fixed-output).
pub trait Hasher {
    /// Output size in bytes.
    const OUTPUT_LEN: usize;
    /// Block size in bytes (for HMAC computation).
    const BLOCK_LEN: usize;

    /// Create a new hasher instance.
    fn new() -> Self;
    /// Feed data into the hasher (can be called multiple times).
    fn update(&mut self, data: &[u8]);
    /// Finalize and return the digest. Consumes the hasher.
    fn finalize(self) -> Vec<u8>;
    /// Finalize into a caller-provided buffer (no allocation).
    fn finalize_into(self, out: &mut [u8]);
    /// One-shot: hash data and return the digest.
    fn hash(data: &[u8]) -> Vec<u8>
    where
        Self: Sized,
    {
        let mut h = Self::new();
        h.update(data);
        h.finalize()
    }
}

/// Trait for extendable-output functions (XOF) such as SHAKE128 / SHAKE256.
///
/// Unlike a fixed-output [`Hasher`], an XOF can be `squeeze`-d for any
/// number of bytes after absorption is complete. The internal sponge
/// state is mutated by every `squeeze` call, so successive squeezes
/// extend the output stream rather than restart it.
pub trait Xof {
    /// Sponge rate (number of bytes absorbed per Keccak-f permutation).
    const BLOCK_LEN: usize;

    /// Create a fresh XOF instance with empty absorbed state.
    fn new() -> Self;
    /// Absorb additional input. May be called any number of times before
    /// the first `squeeze`.
    fn update(&mut self, data: &[u8]);
    /// Squeeze `out.len()` bytes of output. Can be called multiple times;
    /// successive calls extend the same output stream (they do not reset).
    fn squeeze(&mut self, out: &mut [u8]);
}

/// Trait for symmetric block ciphers operating on a fixed block size.
///
/// Implementors include the AES family ([`cipher::Aes`], [`cipher::Aes128`],
/// [`cipher::Aes192`], [`cipher::Aes256`]) and the DES family
/// ([`cipher::Des`], [`cipher::TripleDes`]).
pub trait BlockCipher {
    /// Block size in bytes (16 for AES, 8 for DES / 3DES).
    const BLOCK_LEN: usize;
    /// Key sizes supported by `new`, in bytes.
    const KEY_LENS: &'static [usize];

    /// Initialise the cipher with a key. The key length must be one of
    /// the values listed in [`Self::KEY_LENS`].
    fn new(key: &[u8]) -> Self;
    /// Encrypt `block` in place. The slice must be at least
    /// [`Self::BLOCK_LEN`] bytes long.
    fn encrypt_block(&self, block: &mut [u8]);
    /// Decrypt `block` in place. The slice must be at least
    /// [`Self::BLOCK_LEN`] bytes long.
    fn decrypt_block(&self, block: &mut [u8]);
}

/// Trait for digital signature schemes that produce fixed-shape keys
/// and signatures (no per-call hash parameter).
///
/// **Note**: this trait is currently informational. Most signature
/// schemes in this crate (ECDSA, EdDSA, RSA-PSS, RSA-PKCS1) take a
/// hash function as a generic or runtime parameter and therefore do
/// not implement this trait directly -- they expose their own
/// curve/key types and sign/verify functions. The trait is kept as
/// the canonical "shape" of the simplest signature scheme for
/// future extensions and for documentation purposes.
pub trait SignatureScheme {
    /// Public key type for this scheme.
    type PublicKey;
    /// Secret key type for this scheme.
    type SecretKey;
    /// Signature type.
    type Signature;

    /// Generate a fresh key pair.
    fn keygen() -> (Self::PublicKey, Self::SecretKey);
    /// Sign a message.
    fn sign(sk: &Self::SecretKey, message: &[u8]) -> Self::Signature;
    /// Verify a signature against a message.
    fn verify(pk: &Self::PublicKey, message: &[u8], sig: &Self::Signature) -> bool;
}

/// Trait for public-key encryption schemes.
///
/// Like [`SignatureScheme`], this trait is currently informational --
/// the RSA encryption helpers in [`rsa::pkcs1`] and [`rsa::oaep`] take
/// a parameter of type [`rsa::rsa::RsaPublicKey`] / `RsaSecretKey`
/// directly rather than going through this trait, because OAEP and
/// PKCS#1 v1.5 each take additional protocol parameters (label, RNG)
/// that don't fit the simple shape below.
pub trait PublicKeyEncryption {
    /// Public key type.
    type PublicKey;
    /// Secret key type.
    type SecretKey;

    /// Generate a key pair of the given bit size.
    fn keygen(bits: usize) -> (Self::PublicKey, Self::SecretKey);
    /// Encrypt a plaintext under the public key.
    fn encrypt(pk: &Self::PublicKey, plaintext: &[u8]) -> Vec<u8>;
    /// Decrypt a ciphertext with the secret key. Returns `None` if the
    /// padding does not validate.
    fn decrypt(sk: &Self::SecretKey, ciphertext: &[u8]) -> Option<Vec<u8>>;
}

// ============================================================
// Modules
// ============================================================

/// Hash functions: SHA-1, SHA-2, SHA-3, RIPEMD-160.
pub mod hash;

/// Symmetric ciphers: AES, DES, 3DES.
pub mod cipher;

/// Elliptic curve cryptography: ECDSA, EdDSA.
pub mod ecc;

/// RSA encryption and signatures.
pub mod rsa;

/// Message authentication codes (HMAC, CMAC, KMAC, GMAC).
pub mod mac;

/// Key serialization: DER, PEM, PKCS#1, PKCS#8, SEC1, SPKI.
pub mod encoding;

/// RustCrypto trait bridges (feature-gated).
#[cfg(feature = "rust-crypto-traits")]
pub mod bridge;