krypteia-arcana — Classical Cryptography for the krypteia workspace

Pure-Rust implementations of the classical cryptographic primitives (hashes, symmetric ciphers, MACs, RSA, ECC, EdDSA, Montgomery DH), sharing the side-channel countermeasure toolkit silentops with the post-quantum crate quantica. The crate is the “classical” half of the krypteia workspace.

Design rules

The crate inherits the krypteia workspace design rules:

  1. Pure Rust, zero external crates — only core (and alloc); std is optional behind a feature flag. The only workspace dependency is silentops for shared CT primitives and timing-leak verification.

  2. Embedded-friendly — caller-provided buffers, no hidden heap allocation in the hot path. Target devices: secure elements, STM32 (Cortex-M0/M4/M33), RISC-V (ESP32-C3, …). no_std is on the roadmap.

  3. Side-channel hardened — timing-constant comparisons, deterministic ECDSA nonces (RFC 6979), no secret-dependent branches on the CT-critical paths. AES S-box is table-based (known cache surface, documented below). ECC scalar multiplication uses a CT Montgomery ladder hardened against branch reintroduction by the optimizer.

  4. Validated — every algorithm is tested against pinned RFC / NIST / FIPS reference vectors, plus three external corpora (Wycheproof, NIST CAVP, NIST ACVP).

  5. C FFI-exposable — the companion crate arcana_ffi exports ~20 extern "C" functions with a C header at arcana_ffi/include/arcana.h.

Algorithms

Arcana exposes six primitive families, all in src/:

Hash functions

Algorithm

Output

Module

Standard

SHA-1

160 b

hash::sha1::Sha1 (legacy)

FIPS 180-4

SHA-224

224 b

hash::sha224::Sha224

FIPS 180-4

SHA-256

256 b

hash::sha256::Sha256

FIPS 180-4

SHA-384

384 b

hash::sha384::Sha384

FIPS 180-4

SHA-512

512 b

hash::sha512::Sha512

FIPS 180-4

SHA-512/224

224 b

hash::sha512_trunc::Sha512_224

FIPS 180-4

SHA-512/256

256 b

hash::sha512_trunc::Sha512_256

FIPS 180-4

SHA3-224

224 b

hash::sha3::Sha3_224

FIPS 202

SHA3-256

256 b

hash::sha3::Sha3_256

FIPS 202

SHA3-384

384 b

hash::sha3::Sha3_384

FIPS 202

SHA3-512

512 b

hash::sha3::Sha3_512

FIPS 202

SHAKE128

XOF

hash::sha3::Shake128

FIPS 202

SHAKE256

XOF

hash::sha3::Shake256

FIPS 202

cSHAKE128

XOF

hash::sha3::CShake128

NIST SP 800-185

cSHAKE256

XOF

hash::sha3::CShake256

NIST SP 800-185

BLAKE2b

1-512 b

hash::blake2::Blake2b

RFC 7693

BLAKE2s

1-256 b

hash::blake2::Blake2s

RFC 7693

RIPEMD-160

160 b

hash::ripemd160::Ripemd160 (legacy)

ISO/IEC 10118-3

Symmetric ciphers and modes

Algorithm

Module

Standard

AES-128 / 192 / 256

cipher::aes

FIPS 197

DES, Triple-DES (EDE)

cipher::des

FIPS 46-3

ECB / CBC / CTR / GCM

cipher::modes

NIST SP 800-38A/D

AES-CCM AEAD

cipher::ccm

NIST SP 800-38C, RFC 3610

AES-XTS disk encryption

cipher::xts

IEEE 1619

ChaCha20 stream cipher

cipher::chacha20

RFC 8439

Poly1305 one-time MAC

cipher::poly1305

RFC 8439

ChaCha20-Poly1305 AEAD

cipher::chacha20poly1305

RFC 8439

XChaCha20-Poly1305 AEAD (24B nonce)

cipher::xchacha20poly1305

draft-irtf-cfrg-xchacha

Streaming Cipher ctx

cipher::ctx

The streaming Cipher ctx wraps AES / DES / 3DES with ECB / CBC / CTR behind init / update / finalize, with 5 padding schemes: None, Pkcs7, Iso9797M1 (zero), Iso9797M2 (ISO 7816-4), AnsiX923. AEAD modes stay function-oriented (no unverified plaintext release).

Message authentication codes (MACs)

Family

Algorithms

Standard

HMAC

SHA-1, SHA-256/384/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

NIST SP 800-185

GMAC

AES-128/192/256

NIST SP 800-38D

Three init variants: init(key), init_kmac(key, custom), init_with_nonce(key, nonce). verify accepts truncated tags, constant-time comparison. Poly1305 excluded (one-time MAC, unsafe to reuse via an “init then update again” object).

RSA

Scheme

Module

Standard

PKCS#1 v1.5 enc+sig

rsa::pkcs1

RFC 8017 §7-8

OAEP encryption

rsa::oaep

RFC 8017 §7.1

RSASSA-PSS signature

rsa::pss

RFC 8017 §8.1

Signatures support 8 hash functions: SHA-1, SHA-256/384/512, SHA3-256/384/512, RIPEMD-160.

Elliptic curve cryptography

Seven short-Weierstrass curves behind a unified Curve trait (keygen, ECDSA RFC 6979, ECDSA random-nonce, ECDH, SEC1 compression / decompression, DER signatures):

Wrapper

Curve

Standard

P256

NIST P-256

FIPS 186-5

P384

NIST P-384

FIPS 186-5

P521

NIST P-521

FIPS 186-5

Secp256k1

secp256k1

SEC 2 §2.4.1

BrainpoolP256r1

Brainpool 256-bit

RFC 5639

BrainpoolP384r1

Brainpool 384-bit

RFC 5639

BrainpoolP512r1

Brainpool 512-bit

RFC 5639

The Curve trait + per-curve unit structs live in ecc::curves; the LIMBS-generic ECDSA / ECDH internals live in ecc::ecdsa (signing helpers, DER, RFC 6979) and ecc::curve (Jacobian point ops + curve params).

Edwards / Montgomery curves

Algorithm

Module

Standard

Ed25519 (pure)

ecc::eddsa

RFC 8032 §5.1

Ed25519ctx

ecc::eddsa

RFC 8032 §5.1.6

Ed25519ph

ecc::eddsa

RFC 8032 §5.1.7

X25519 ECDH

ecc::x25519

RFC 7748

X448 ECDH

ecc::x448

RFC 7748

Ed448 is planned but not yet implemented (RFC 8032 Appendix A port pending).

Cargo features

[dependencies]
arcana = { path = "../arcana" }   # default = no features

Feature

Default

Effect

std

Reserved for future no_std work (currently a no-op; the crate already only uses core + alloc).

rust-crypto-traits

Pulls in digest 0.10 / cipher 0.4 / signature 2.0. 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 for callers who need to plug arcana hashes into the RustCrypto ecosystem.

Quick start

Hashing (SHA-256)

use arcana::hash::sha256::Sha256;
use arcana::Hasher;

let digest = Sha256::hash(b"hello, arcana");
assert_eq!(digest.len(), 32);

AEAD (AES-128-GCM)

use arcana::cipher::aes::Aes128;
use arcana::cipher::modes::Gcm;
use arcana::BlockCipher;

let cipher = Aes128::new(&[0x42u8; 16]);
let nonce = [0u8; 12];
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");

X25519 ECDH

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);

HMAC-SHA-256 (streaming)

use arcana::mac::ctx::{Mac, Algorithm};

let mut m = Mac::new(Algorithm::HmacSha256);
m.init(b"secret key").unwrap();
m.update(b"hello, ").unwrap();
m.update(b"world!").unwrap();
let tag = m.sign_to_vec().unwrap();
assert_eq!(tag.len(), 32);

AES-256-CBC (Cipher ctx)

use arcana::cipher::ctx::{Cipher, Algorithm, Mode, Padding, Direction};

let mut c = Cipher::new(Algorithm::Aes256, Mode::Cbc, Padding::Pkcs7).unwrap();
c.init(Direction::Encrypt, &[0x42u8; 32], &[0x77u8; 16]).unwrap();
let mut out = vec![0u8; 64];
let mut n = c.update(b"hello, streaming!", &mut out).unwrap();
n += c.finalize(&mut out[n..]).unwrap();
out.truncate(n);
// out now contains the padded AES-256-CBC ciphertext.

Typed key wrappers (Zeroize-on-Drop)

Arcana exposes typed key types for RSA, EdDSA, and the seven short-Weierstrass curves, but none of them currently implement Drop with silentops::ct_zeroize. Callers must zeroize sensitive buffers explicitly until the wrappers grow Zeroize-on-Drop — this gap is tracked under Known limitations → Side-channel.

Module

Public

Secret (currently NOT zeroized on drop)

ecc::curves

PublicKey

SecretKey

ecc::eddsa

Ed25519PublicKey

Ed25519SecretKey

rsa::rsa

RsaPublicKey

RsaSecretKey (n, d, p, q, dp, dq, qinv as BigInt)

The X25519 / X448 APIs operate on raw [u8; 32] / [u8; 56] byte arrays today; a typed wrapper layer is a candidate refresh once the ECC SecretKey wrapper grows Drop.

silentops::ct_zeroize is available to callers as the canonical volatile-write zeroizer (it relies on core::ptr::write_volatile + a compiler fence so the compiler cannot elide the writes); apply it to bytes fields of secret-key types before they go out of scope on the caller side.

Parameter sets / curve families

NIST P-curves

Curve

Field prime

Order bit length

felem (B)

sec. level

P-256

2^256 2^224 + 2^192 + 2^96 1

256

32

128

P-384

2^384 2^128 2^96 + 2^32 1

384

48

192

P-521

2^521 1 (Mersenne)

521

66

256

P-521 is the only curve where the SEC1 octet width (66 B) does not match the internal storage width (LIMBS * 8 = 72 B). The serialization layer strips / left-pads the 6 leading zero bytes at the boundary.

Brainpool

Curve

Field prime size

Order bit length

felem (B)

Source

brainpoolP256r1

256 bits

256

32

RFC 5639

brainpoolP384r1

384 bits

384

48

RFC 5639

brainpoolP512r1

512 bits

512

64

RFC 5639

secp256k1

Curve

Field prime

Order bit length

felem (B)

Source

secp256k1

2^256 2^32 977

256

32

SEC 2 §2.4.1

y^2 = x^3 + 7 (a = 0, b = 7). The Bitcoin / Ethereum signing curve.

Edwards / Montgomery

Family

Curve

Wire size (B)

Source

Edwards

Ed25519

32 (pk), 32 (sk), 64 (sig)

RFC 8032 §5.1

Edwards

Ed448

(planned)

RFC 8032 §5.2

Montgomery

X25519

32 (pk = sk = ss)

RFC 7748

Montgomery

X448

56 (pk = sk = ss)

RFC 7748

RSA key sizes

The rsa::rsa::rsa_keygen constructor accepts arbitrary bit lengths (within the bounds of the BigInt arithmetic). Tested values: 1024, 2048, 3072, 4096. Keys above 4096 bits work but key generation gets slow (BigInt multi-precision is unoptimized). For typical TLS/CMS usage 2048 or 3072 are the right defaults; 4096 is documented but expensive.

Design decisions

  1. Function-oriented API + streaming objects — one-shot functions (Sha256::hash, Gcm::encrypt, P256::sign_rfc6979) for the common case; Cipher and Mac streaming objects for callers that feed data in chunks or need caller-provided buffers without heap.

  2. Hash function is always explicit — ECDSA, RSA-PSS, RSA-PKCS1 all take the hash as a type or enum parameter. No hidden default.

  3. AEAD stays function-oriented — GCM, CCM, ChaCha20-Poly1305, XChaCha20-Poly1305 are not routed through the streaming Cipher to avoid releasing unverified plaintext during streaming decryption.

  4. Curve trait unifies ECDSA + ECDH + SEC1 — all 7 short- Weierstrass curves are unit structs implementing one trait, so the same code works for P-256 and BrainpoolP512r1 with just a type change.

  5. Three MAC init variantsinit(key) for HMAC/CMAC/KMAC, init_kmac(key, S) for KMAC with customization, init_with_nonce for GMAC. Wrong variant → compile-time or runtime error.

  6. Poly1305 excluded from Mac ctx — it is a one-time MAC; reusing the key breaks it. Keeping it function-oriented prevents misuse.

  7. CT scalar mul splitscalar_mul_point calls the ladder-only point_add_ct (no branches on point coords); the variable point_add (with H==0 short-circuits) is reserved for double_scalar_mul, used by ECDSA verify on public values.

Side-channel countermeasures (summary)

Always-on

These defences are active in every build, regardless of feature flags:

Defence

Scope

Constant-time tag comparison

All AEAD decrypt, MAC verify, ECDSA verify

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

field_add / field_sub / reduce_wide masks, to keep LLVM from recovering branches

No secret-dependent branches

Hash, symmetric, HMAC, CMAC, KMAC, GMAC

RFC 6979 deterministic nonce

ECDSA — eliminates nonce-reuse attacks

silentops::ct_zeroize available

Caller can zeroize buffers holding secrets explicitly

Feature-gated

Arcana does not ship a feature-gated SCA layer today. Algorithm choice is the only knob: prefer the curve / cipher with the strongest intrinsic CT properties for your threat model (e.g. Curve25519 over NIST P-curves on cache-shared targets, ChaCha20-Poly1305 over AES-GCM on cores without AES-NI).

A sca-protected feature mirroring the quantica side (masking + shuffled NTT) is on the roadmap for symmetric primitives whose state is amenable; classical curves are protected algorithmically (CT ladder) rather than by masking.

Timing leakage verification (dudect)

The shared silentops::verify module implements the dudect methodology of Reparaz, Balasch & Verbauwhede (2017). Arcana does not yet ship a pre-built dudect harness of its own; instructions for hooking new test scenarios into the workspace harness live in silentops/examples/ct_verify_pqc.rs (the post-quantum harness) — mirror that file with arcana primitives when running a CT campaign.

The eventual third-party evaluation pass will require dudect runs on:

  • scalar_mul_point (the Montgomery ladder) — already audited at release-asm level: 0 secret-dependent branches in the loop body.

  • field_inv / scalar_inv (Fermat’s little theorem ladder).

  • RSA CRT decrypt path (rsa::rsa::rsa_decrypt_raw).

  • AEAD decrypt tag compare (constant-time via silentops::ct_eq).

A t-statistic with |t| < 4.5 after ~10⁶ samples is considered passing (p < 10⁻⁵).

Known residual surface

The following attack surfaces are not defended against and are documented here so the reader knows what they are deploying:

Primitive

Issue

Mitigation path

AES S-box

Table-based lookup — cache-line leak

Bitsliced / AES-NI backend (not yet shipped)

DES / 3DES S-boxes

Table-based

Legacy only; avoid on SCA-sensitive targets

RSA CRT decrypt

BigInt ops not formally CT-audited

Audit + dudect run scheduled

Heap allocations

Secret-key buffers come from alloc

Caller-provided fixed buffers (planned refactor)

Zeroize-on-Drop

Typed key wrappers do not yet Drop

Wrap secret types with silentops::ct_zeroize

DPA / EM / fault

Out of scope for software library

See workspace-level SCA design docs

Compiler CMOV

Bit-mask CT depends on black_box

silentops asm backends on x86_64 / aarch64

Per-algorithm deep dives

The summary above lists which countermeasures are active; the full per-algorithm SCA analyses — threat matrices, attack references, code pointers, residual risks — live under arcana/doc/sca/countermeasures/ in the repository. The Sphinx documentation pack (./gendoc.sh arcana) inlines them as a navigable cross-linked tree below.

Performance

Arcana does not yet ship a dedicated benchmarking crate (no arcana_bench companion exists at workspace level). Representative single-threaded numbers obtained from cargo test --release timings on x86_64 desktop hardware:

Algorithm

KeyGen / setup

Sign / Encrypt

Verify / Decrypt

AES-128-GCM (1 KiB)

< 0.01 ms

< 0.01 ms

ChaCha20-Poly1305

< 0.01 ms

< 0.01 ms

SHA-256 (1 KiB)

< 0.01 ms

RSA-2048 (PKCS#1)

~150 ms

~6 ms

< 0.5 ms

ECDSA P-256

~1 ms

~3 ms

~3 ms

Ed25519

< 0.1 ms

< 0.1 ms

< 0.5 ms

X25519

< 0.1 ms

< 0.1 ms

Numbers are coarse and should not be cited; they vary widely with hardware and feature flags. A proper Criterion-based bench harness mirroring quantica_bench is on the roadmap.

Building

Desktop / server (default)

# Build everything (opt-level=2, CT-safe)
cargo build --release -p arcana

# Build with the RustCrypto trait bridge feature
cargo build --release -p arcana --features rust-crypto-traits

# Run all tests
cargo test --release -p arcana

# Generate the rustdoc API reference (strict mode: -D warnings -D missing-docs)
RUSTDOCFLAGS="-D warnings -D missing-docs" cargo doc -p arcana --no-deps

Both the default and the rust-crypto-traits configurations pass strict-doc mode with zero warnings.

no_std / bare-metal cross-compile

The crate is still in transition: it currently uses Vec<u8> / alloc end-to-end and the std feature is reserved as a no-op for future use. Bare-metal cross-compilation will work once the caller-provided-buffer refactor lands; today it is only verified at the workspace level for quantica. Targeted rustc targets:

# Install the targets we care about
rustup target add thumbv6m-none-eabi          # Cortex-M0/M0+
rustup target add thumbv7em-none-eabihf       # Cortex-M4/M7
rustup target add thumbv8m.main-none-eabihf   # Cortex-M33 (TrustZone)
rustup target add riscv32imc-unknown-none-elf # ESP32-C3, SiFive

Cargo profiles

The workspace Cargo.toml declares three profiles:

Profile

opt-level

CT guarantee

Use case

release

2

Yes (Rust source-level + black_box)

Desktop / server production

release-embedded

z + abort

Yes (asm CT backends from silentops)

Embedded, minimum size

release-bench

3

No (LLVM may break CT patterns)

Benchmarks only

⚠️ opt-level=3 can defeat constant-time guarantees: LLVM may convert bitwise mask patterns into conditional memory accesses. Always use opt-level=2 or lower for security-critical builds, or rely on the assembly CT backends from silentops (asm-aarch64, asm-thumbv7, asm-thumbv6m, asm-riscv32) which bypass the compiler entirely.

Test validation

All implementations are validated against four independent vector suites; total ≈ 351 tests in the default build (358 with rust-crypto-traits).

NIST CAVP / FIPS / RFC happy-path conformance

The bulk of the conformance evidence comes from RFC and FIPS pinned vectors (in-source tests, arcana/src/**/tests) plus the official NIST CAVP .rsp corpus mirrored under arcana/tests/cavp/:

Family

# tests

Vector sources

SHA-1/2 family

~25

FIPS 180-4 examples, NIST CAVP, RFC 6234

SHA3 / SHAKE / cSHAKE

~25

FIPS 202 examples, NIST SP 800-185 sample 1/2/4

BLAKE2

~10

RFC 7693 §B test vectors

AES (all modes)

~40

FIPS 197, NIST SP 800-38A/B/C/D, IEEE 1619, RFC 4493

ChaCha20-Poly1305

~15

RFC 8439 §2.8 + draft-irtf-cfrg-xchacha §3

RSA

~20

PKCS#1 / OAEP / PSS round-trips, RFC 8017 §A.1

ECDSA

~50

RFC 6979 §A.2, NIST P-256/384/521 generators, 7 curves

EdDSA

~25

RFC 8032 §7.1 (Ed25519 pure + ctx + ph)

X25519 / X448

~20

RFC 7748 §6

HMAC

~15

RFC 4231, RFC 2202

CMAC / KMAC / GMAC

~20

RFC 4493, NIST SP 800-185, NIST SP 800-38D

Streaming Cipher / Mac ctx

~40

Round-trips × (mode × padding), error paths

DER / PEM key serialization

~10

PKCS#1, SEC1, SPKI, PKCS#8 round-trips

CAVP corpus

~2 200

NIST CAVP .rsp (SHA, AES, HMAC, ECDSA SigVer)

ACVP corpus

~1 250

NIST ACVP JSON (SHA3, AES-CTR/CCM/XTS, HMAC-SHA3, ECDSA SigVer)

Wycheproof

Vectors from the C2SP/wycheproof project, covering malformed inputs, corrupted keys, oversized DER INTEGERs, edge-case ECDSA signatures, and other negative tests the NIST happy-path vectors do not exercise. Each vector carries a result field — valid, invalid, or acceptable — against which the implementation’s accept / reject decision is compared.

Family

Vectors

Notes

AES-GCM

~250

invalid IVs, tag truncation, corrupted ciphertext

AES-CBC-PKCS5

~180

padding-oracle robustness

ChaCha20-Poly1305

~120

RFC 8439 negatives

ECDSA P-256

~380

edge cases on r/s, oversized DER (also closed a real bug)

ECDSA P-384

~270

same edge-case set on the larger curve

EdDSA Ed25519

~160

RFC 8032 §5.1 corner cases

RSA OAEP / PSS

~240

wrong hash, modulus length, label

HMAC-SHA-2

~70

wrong key length, truncated tags

Total

~1 670

The Wycheproof import surfaced (and we fixed) one ECDSA oversized-s bug — see commit 191d40e.

Custom negative / robustness tests

Hand-curated tests targeting the specific error paths of each typed key wrapper — wrong-length inputs, off-curve public keys (defence against the invalid-curve attack), tampered signatures, infinity encodings, malformed DER, etc. Around 30 tests across the families.

Running everything

cargo test --release -p arcana
cargo test --release -p arcana --features rust-crypto-traits

Policy on test suites

A necessary condition for adding a new cryptographic primitive to this crate is the availability of a public reference test suite for it. When a new peer-reviewed test corpus appears — a refreshed Wycheproof release, a new CAVP tranche, an IETF CFRG vector set — we import it and extend the test matrix accordingly, and call the refresh out in the changelog.

Examples

Rust

cargo run -p arcana --release --example hash_demo     # SHA-256, SHA3, SHAKE
cargo run -p arcana --release --example aes_demo      # AES-128-GCM encrypt/decrypt
cargo run -p arcana --release --example rsa_demo      # RSA-2048 sign + OAEP encrypt
cargo run -p arcana --release --example ecdsa_demo    # ECDSA P-256 keygen/sign/verify
cargo run -p arcana --release --example eddsa_demo    # Ed25519 sign/verify
cargo run -p arcana --release --example x25519_demo   # X25519 ECDH key exchange

C FFI

For C consumers, the arcana_ffi companion crate exposes ~20 extern "C" functions and ships a standalone test_arcana.c example program. Build the shared library and run the C test:

cargo build --release -p arcana_ffi
gcc -O2 -o test_arcana arcana_ffi/examples/test_arcana.c \
    -Iarcana_ffi/include -Ltarget/release -larcana_ffi -lpthread -ldl -lm
LD_LIBRARY_PATH=target/release ./test_arcana

The generated C header (arcana.h) is kept under the FFI crate’s include/ directory.

Module map

arcana/src/
  lib.rs                    Crate root: Hasher, Xof, BlockCipher traits
  hash/
    mod.rs                  Re-exports
    sha1.rs                 SHA-1 (FIPS 180-4) — legacy
    sha224.rs               SHA-224
    sha256.rs               SHA-256
    sha384.rs               SHA-384
    sha512.rs               SHA-512
    sha512_trunc.rs         SHA-512/224, SHA-512/256
    sha3.rs                 SHA3-224/256/384/512, SHAKE128/256, cSHAKE128/256
    blake2.rs               BLAKE2b, BLAKE2s (RFC 7693)
    ripemd160.rs            RIPEMD-160 (ISO 10118-3) — legacy
  cipher/
    mod.rs                  Re-exports
    aes.rs                  AES-128/192/256 (FIPS 197, table-based S-box)
    des.rs                  DES + Triple-DES (FIPS 46-3)
    modes.rs                ECB, CBC, CTR, GCM (SP 800-38A/D)
    ccm.rs                  AES-CCM AEAD (SP 800-38C, RFC 3610)
    xts.rs                  AES-XTS disk encryption (IEEE 1619)
    chacha20.rs             ChaCha20 stream cipher (RFC 8439)
    poly1305.rs             Poly1305 one-time MAC (RFC 8439)
    chacha20poly1305.rs     ChaCha20-Poly1305 AEAD (RFC 8439)
    xchacha20poly1305.rs    XChaCha20-Poly1305 AEAD (24-byte nonce)
    ctx.rs                  Streaming Cipher: init/update/finalize + padding
  mac/
    mod.rs                  Re-exports
    ctx.rs                  Streaming Mac: HMAC×8, CMAC×4, KMAC×2, GMAC×3
  rsa/
    mod.rs                  Re-exports
    bigint.rs               Arbitrary-precision integer arithmetic
    rsa.rs                  Key generation, raw encrypt/decrypt (CRT)
    pkcs1.rs                PKCS#1 v1.5 enc + sig (8 hash functions)
    oaep.rs                 RSAES-OAEP (RFC 8017 §7.1)
    pss.rs                  RSASSA-PSS (RFC 8017 §8.1)
  ecc/
    mod.rs                  Re-exports
    field.rs                Multi-precision field arithmetic (P-256..P-521, Curve25519, Curve448)
    curve.rs                Short-Weierstrass curve params + Jacobian point ops + CT scalar_mul_point
    curves.rs               Curve trait + 7 unit structs + dispatch macro (shared ECDSA/ECDH)
    ecdsa.rs                ECDSA Signature + DER + RFC 6979 + LIMBS-generic internals
    ecdh.rs                 ECDH integration tests (impl lives in ecdsa.rs)
    eddsa.rs                Ed25519 pure + ctx + ph (RFC 8032)
    x25519.rs               X25519 ECDH (RFC 7748)
    x448.rs                 X448 ECDH (RFC 7748)
  encoding/
    mod.rs                  Re-exports
    der.rs                  DER encoder / parser (canonical, strict)
    pem.rs                  PEM armor / dearmor
    keys.rs                 PKCS#1 / SEC1 / SPKI / PKCS#8 key serialization
  bridge/
    mod.rs                  RustCrypto digest::Digest adapters (feature-gated)

Known limitations

Side-channel protection

  • AES uses a table-based S-box — vulnerable to cache-timing on shared L1 targets. Bitsliced / AES-NI backend is not yet shipped.

  • DES / 3DES use table-based S-boxes; legacy use only.

  • RsaSecretKey / Ed25519SecretKey / SecretKey (ECC) lack Zeroize-on-Drop. Callers must zeroize sensitive buffers explicitly via silentops::ct_zeroize.

  • Heap allocations on the secret path — secret-key buffers come from alloc rather than caller-provided fixed buffers. A future refactor will thread &mut [u8] end-to-end for bare-metal stack-only operation.

  • RSA CRT decrypt path (rsa::rsa::rsa_decrypt_raw) has not been formally CT-audited; a BigInt review + dudect run is scheduled.

  • Bit-mask CT primitives are defended against LLVM branch-recovery via core::hint::black_box; on targets without the silentops asm backend (e.g. WebAssembly) the CT guarantee is best-effort source-level only.

Standards conformance

  • Ed448 is not yet implemented (RFC 8032 Appendix A port pending — prior WebFetch attempts to fetch the RFC reference Python were inconsistent).

  • AES-OCB (RFC 7253) is not implemented; will be added on demand.

  • DER/PEM key serialization covers PKCS#1, SEC1, SPKI, PKCS#8; ASN.1 BER (non-canonical) input is rejected by design.

Portability

  • The crate depends on alloc (Vec<u8> everywhere); a true no_std mode requires the caller-provided-buffer refactor noted above.

  • No platform-specific OsRng adapter; ECDSA and RSA keygen take a user-supplied RNG callback. The caller is responsible for wiring a hardware-RNG / BCryptGenRandom / SecRandomCopyBytes / /dev/urandom source on their target.

Testing

  • No fuzz harness yet (cargo-fuzz is on the roadmap).

  • No CI/CD pipeline yet — the workspace .gitea/workflows/ will cover the test matrix once the post-quantum side closes its CT3 (QEMU-user) milestone.

  • No formal third-party evaluation yet; arcana feeds the same documentation pack as quantica and is aimed at the same evaluation target.

Roadmap

The full hardening roadmap lives under arcana/doc/sca/ (HTML rendered by ./gendoc.sh arcana). The summary below is the project’s living plan towards a third-party evaluation, indexed by Tier item identifier so each row maps to a stable cross-reference in the source code, the SCA annex and the workspace SECURITY.md lifecycle.

Status legend: ✅ done · 🔧 in progress · 📋 planned · 💤 deferred.

Tier 1 — Active vulnerabilities (critical path)

Id

Item

Status

T1-A

Fixsliced AES (Adomnicai-Peyrin TCHES 2021/1) — replace table-based S-box

📋

T1-B

Minerva audit on bits2int / reduce_mod_n / scalar_inv / sample_random_scalar

📋

T1-C

Aumüller RSA-CRT against Bellcore (formally verified by Rauzy-Guilley)

📋

T1-D

Hedged ECDSA / EdDSA mode (CFRG det-sigs-with-noise)

📋

T1-E

RSA bigint CT audit (Montgomery_mul, cmp, pow_mod, mod_inv)

📋

T1-F

Ed25519 scalar-mul audit (mirror of 76191c1)

📋

T1-G

X25519 / X448 ladder audit + black_box shielding

📋

Tier 2 — Hardening for evaluation

Id

Item

Status

T2-A

Z-coordinate randomization (Brier-Joye 2002) on ECC

📋

T2-B

Scalar blinding (Coron 1999) on ECC

📋

T2-D

First-order Boolean masking of SHA-2 (Belenky TCHES 2023/3 — CDPA)

📋

T2-E

Zeroize-on-Drop on RsaSecretKey, Ed25519SecretKey, ECC SecretKey

📋

T2-G

First-order Boolean masking on fixsliced AES (post T1-A)

📋

T2-H

CT carry-less GHASH multiplier (PCLMULQDQ / PMULL on host; bitsliced on embedded)

📋

T2-I

RSA message blinding + exponent blinding (Coron 1999)

📋

T2-J

PKCS#1 v1.5 CT padding-oracle handling (RFC 8017 §7.2.2)

📋

T2-K

X25519 / X448 small-subgroup contributory check audit

📋

Tier 3 — Verification tooling

The cross-arch test infrastructure tracked under quantica’s T3-A / T3-B (qemu-user matrix on the three non-x86_64 Linux triplets, qemu-system matrix on the bare-metal targets, and the semihosting host↔guest vector-streaming protocol — see .forgejo/workflows/qemu-cross-tests.yml, Cross.toml, and the tools/qemu-*.sh drivers) is workspace-wide and already exercises arcana — cross test --target aarch64-unknown-linux-gnu -p arcana runs the full 315-vector arcana KAT set under qemu-user with the asm-aarch64 silentops backend on every PR. arcana’s own Tier 3 rows below cover the additional CT-evidence harnesses (ctgrind / dudect) that are not subsumed by the cross-arch matrix.

Id

Item

Status

T3-A

ctgrind harness (mirror of quantica’s, via silentops::ct_grind)

📋

T3-B

dudect harness on scalar_mul_point, rsa_decrypt, AEAD decrypt, fixsliced AES

📋

Tier 4 — Deferred / beyond the current evaluation scope

Id

Item

Status

T4-RSA-A

Joye-Tunstall infective computation (multi-fault resistance)

💤

T4-AES-A

AES last-round redundancy + infective DFA defence

💤

T4-CC

Higher-order DPA / template (2-share masking) for CC EAL4+

💤

Tier 5 — Documentation pass

Cross-cutting documentation work, orthogonal to the cryptographic tiers above. Planned (not deferred); timing to be sequenced against the external evaluation calendar. Items are workspace-wide and shared with the quantica Tier 5.

Id

Item

Status

T5-A

Workspace-wide doc pass (quantica + arcana): neutralise evaluation-target references — replace any CSPN-/ANSSI-specific language with generic evaluation / certification / audit terminology so the doc set reads cleanly against any third-party reviewer

T5-B

TOC review across the workspace doc set (doc/TOC.md contract + per-crate doc/ trees) — reorder chapters into 4 thematic clusters; rename ch.8 “Side-channel countermeasures” → “(summary)” + add Per-algorithm deep dives H3 bridging to the Sphinx pack

ECC follow-ups (already shipped)

Id

Item

Status

ecc::curves split (Curve trait + unit structs out of ecdsa.rs)

✅ commit 0feb5b5

CT hardening of scalar_mul_point (Montgomery ladder, branchless point_add_ct, core::hint::black_box shielding on field_* masks)

✅ commit 76191c1

Ed448

RFC 8032 Appendix A port

💤 (RFC fetch fragile, deferred until reference Python is available locally)

AES-OCB

RFC 7253

💤 (skip unless explicit ask)

Suggested execution order (critical path)

  1. Sprint 1: T1-A + T1-C + T1-E — closes the active attack surface.

  2. Sprint 2: T2-A + T2-B + T2-E + T1-B Minerva audit — hardens ECC to SOTA.

  3. Sprint 3: T3-A ctgrind + T3-B dudect — provides CT evidence for the eval.

  4. Sprint 4: T1-D hedged + T2-D HMAC masking — final hardening.

  5. Evaluation doc pack ships, referencing each countermeasure to its paper.

Effort estimate: 4 – 6 weeks full-time for T1 + T2 + T3, plus ~2 weeks documentation. Updates to this table are tracked in the change log of arcana/doc/sca/index.rst.

References

License

Apache-2.0.