tc_twofish 0.1.0

Twofish block cipher with 128-, 192- and 256-bit keys and a 128-bit block.
Documentation

tc_twofish

crates.io docs.rs CI license rustc

The Twofish block cipher, an AES finalist, with a 128-, 192- or 256-bit key and a 128-bit block. The engine implements the tc_block_cipher traits.

The crate is no_std, needs no allocator and contains no unsafe code. It depends on tc_block_cipher and tc_zeroize.

Requires Rust 1.85 or later (edition 2024).

Types

  • TwofishEngine — Twofish with a 16-, 24- or 32-byte key and a 16-byte block; variable time.

The engine takes its key through any KeyParams, such as KeyRef. Another key length returns InitError::InvalidKeyLength and keeps the previous key. process_block transforms the first block and returns its length, returning BlockError::NotInitialised before init and BlockError::BufferTooShort for a buffer shorter than a block, without touching the output. Display writes "Twofish" without inspecting key material.

The constants ALGO_NAME, BLOCK_BYTES and KEY_BYTES hold the name, the block length, 16, and the accepted key lengths, [16, 24, 32]. The engine implements Default and has const fn new.

Usage

[dependencies]
tc_twofish = "0.1.0"
tc_block_cipher = "0.1.0"
use tc_block_cipher::{BlockCipher, BlockCipherInit, CipherDirection, KeyRef};
use tc_twofish::TwofishEngine;

let key = [0x42; 32];
let mut engine = TwofishEngine::new();
engine
    .init(CipherDirection::Encrypt, &KeyRef::new(&key))
    .expect("Twofish accepts a 32-byte key");
let mut ciphertext = [0; 16];
assert_eq!(engine.process_block(&[0x11; 16], &mut ciphertext), Ok(16));

The crate and engine documentation carry executable examples.

Security

The engine is variable time: block processing looks up key-dependent S-box and MDS tables with secret data, and key setup branches on secret data, so timing can leak the key. Use it only where timing leakage is outside the threat model; this crate provides no constant-time engine.

The engine keeps its expanded tables and subkeys rather than borrowing the caller's key, and wipes them when they are replaced and on drop. Wiping does not reach the caller's key buffer or copies left in registers and on the stack.

This is a block-cipher primitive, not a message-encryption format. It supplies no padding, mode of operation or authentication.

Validation

The engine is tested against the vectors of Bouncy Castle's TwofishTest for every key length, in both directions, and the published all-zero vector, and against RustCrypto's twofish on the known vector and 64 further key and block pairs. Contract tests cover error state, untouched output on errors and preserved output tails. A test requires every engine API to document whether it is constant or variable time.

Missing public documentation and unsafe code are rejected by crate-level lints.

Run these commands from the workspace root:

cargo test -p tc_twofish --locked
cargo clippy -p tc_twofish --all-targets --locked -- -D warnings
cargo fmt -p tc_twofish --check
cargo doc -p tc_twofish --no-deps --locked

Before a release, check the archive contents and run publication validation from a committed checkout:

cargo package -p tc_twofish --list --locked
cargo publish -p tc_twofish --dry-run --locked

The archive includes both license texts, this README, the changelog, the source and the integration tests. It must not include target/ or other build artifacts.

License

Licensed under either the MIT license or the Apache License, Version 2.0, at your option.