Skip to main content

ic_cipher/
lib.rs

1//! # ic-cipher — block ciphers, stream ciphers, and AEADs
2//!
3//! Pure-Rust, `no_std`, dependency-free implementations of AES (FIPS 197),
4//! the SP 800-38A confidentiality modes, AES-GCM (SP 800-38D), and the
5//! RFC 8439 ChaCha20-Poly1305 suite.
6//!
7//! ```
8//! use ic_cipher::Aes256Gcm;
9//! use ic_core::traits::Aead;
10//!
11//! let cipher = Aes256Gcm::new(&[0x2a; 32])?;
12//! let mut buf = *b"ship it";
13//! let mut tag = [0u8; 16];
14//! cipher.seal_detached(&[0u8; 12], b"context", &mut buf, &mut tag)?;
15//! cipher.open_detached(&[0u8; 12], b"context", &mut buf, &tag)?;
16//! assert_eq!(&buf, b"ship it");
17//! # Ok::<(), ic_core::Error>(())
18//! ```
19//!
20//! ## Backend status
21//!
22//! This is the **portable constant-time backend**. AES computes its S-box
23//! algebraically and GHASH multiplies bit by bit, so neither touches a
24//! key-dependent memory address — the cache-timing channel that table-driven
25//! AES leaves open is closed by construction. The cost is throughput: expect
26//! single-digit MB/s rather than the GB/s an AES-NI or bitsliced backend
27//! delivers. Hardware backends are a planned addition behind the same traits,
28//! and the ontology reports which backend is active via
29//! `ic_ontology::runtime::backend()`, so an agent can decide whether a workload
30//! belongs here.
31#![cfg_attr(not(feature = "std"), no_std)]
32#![deny(missing_docs)]
33// Every unsafe operation inside an unsafe fn must be marked explicitly, so the
34// SIMD backends cannot smuggle one in under the function signature.
35#![forbid(unsafe_op_in_unsafe_fn)]
36// And unsafe may only appear where a CPU intrinsic is being called, which is
37// what the allowances below mark. Everywhere else in this crate -- the modes,
38// the key wrapping, the field arithmetic -- it is a compile error.
39#![deny(unsafe_code)]
40#![warn(clippy::all)]
41
42// AES-NI and the ARMv8 crypto extensions, behind runtime detection.
43#[allow(unsafe_code)]
44pub mod aes;
45
46// AVX2 for the ChaCha20 keystream, behind runtime detection.
47#[allow(unsafe_code)]
48pub mod chacha;
49#[cfg(all(target_arch = "x86_64", feature = "std"))]
50// The carry-less multiply instruction.
51#[allow(unsafe_code)]
52mod clmul;
53// GHASH via CLMUL when the CPU has it.
54#[allow(unsafe_code)]
55pub mod gcm;
56pub mod gcm_siv;
57pub mod gf;
58pub mod keywrap;
59pub mod modes;
60pub mod polyval;
61
62pub use aes::{Aes128, Aes192, Aes256};
63pub use chacha::{chacha20_xor, ChaCha20Poly1305, Poly1305};
64pub use gcm::{Aes128Gcm, Aes192Gcm, Aes256Gcm, GcmLimits};
65pub use gcm_siv::{Aes128GcmSiv, Aes256GcmSiv};
66pub use keywrap::{Aes128Kw, Aes128Kwp, Aes192Kw, Aes192Kwp, Aes256Kw, Aes256Kwp};
67pub use modes::{cbc_decrypt, cbc_encrypt, ctr_xor, pkcs7_pad, pkcs7_unpad};
68
69/// Ontology identifiers for the AEADs this crate provides.
70pub const AEAD_IDS: &[&str] = &[
71    "aes-128-gcm",
72    "aes-192-gcm",
73    "aes-256-gcm",
74    "chacha20-poly1305",
75];
76
77/// Ontology identifiers for the raw block ciphers this crate provides.
78pub const BLOCK_CIPHER_IDS: &[&str] = &["aes-128", "aes-192", "aes-256"];