mtp/crypto
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Alex Emmet 6ef1293603
Some checks failed
CI / rustfmt (push) Failing after 17s
CI / wasm build (push) Failing after 1m13s
CI / clippy (push) Failing after 1m17s
CI / example (push) Failing after 1m30s
CI / test (push) Successful in 1m50s
CI / duplicate code (push) Failing after 31s
CI / web client (push) Failing after 31s
CI / cargo-machete (push) Successful in 1m15s
CI / cargo-deny (push) Failing after 2m26s
[Add] Ease of use functions
2026-06-28 03:26:07 +02:00
..
src [Add] Ease of use functions 2026-06-28 03:26:07 +02:00
Cargo.lock Gitignores 2026-06-27 02:00:42 +02:00
Cargo.toml (feat): add package.json for easy wasm installs 2026-06-27 02:32:43 +02:00
README.md Host & Client force randomness on each other. 2026-06-26 17:08:48 +02:00

mtp-crypto

Cryptographic primitives for the MTP protocol. Classical and post-quantum.

Features

Feature Primitives Status
default XChaCha20-Poly1305, Ed25519, HKDF-SHA-256, SHA-256 Classical
full default + AES-256-GCM Classical
pqc ML-KEM-768+X25519 hybrid KEM, ML-DSA-65 Post-quantum

AEAD

XChaCha20-Poly1305 (default) and AES-256-GCM (full feature). Nonce is prepended to ciphertext.

use mtp_crypto::{ChaCha20Poly1305, AeadEncrypt, AeadDecrypt};

let cipher = ChaCha20Poly1305::new([0u8; 32]);
let ct = cipher.encrypt(b"hello", b"aad")?;
let pt = cipher.decrypt(&ct, b"aad")?;

Signatures

Ed25519

use mtp_crypto::{Ed25519Signer, SignatureScheme};

let (signer, sk, pk) = Ed25519Signer::generate();
let sig = signer.sign(b"message")?;
signer.verify(b"message", &sig)?;

ML-DSA-65

use mtp_crypto::{MlDsaSigner, SignatureScheme};

let (signer, sk, pk) = MlDsaSigner::generate();
let sig = signer.sign(b"message")?;
signer.verify(b"message", &sig)?;

// Load from stored bytes
let signer = MlDsaSigner::new(&sk, &pk)?;

Dual signatures

use mtp_crypto::{sign_dual, DualSignature, Ed25519Signer, MlDsaSigner};

let (ed_signer, _, _) = Ed25519Signer::generate();
let (ml_signer, _, _) = MlDsaSigner::generate();
let dual = sign_dual(ed_signer.signing_key(), ml_signer.signing_key(), b"msg");
dual.verify(ed_signer.verifying_key(), ml_signer.verifying_key(), b"msg")?;

Hybrid KEM

X25519 + ML-KEM-768. 64-byte shared secret. Feed into HKDF before use.

use mtp_crypto::HybridKem;

let (sk, pk) = HybridKem::generate_keypair();
let enc = HybridKem::encapsulate(&pk)?;
let ss = HybridKem::decapsulate(&sk, &enc.ciphertext)?;
assert_eq!(enc.shared_secret, ss);

KDF

use mtp_crypto::{hkdf_expand, derive_encryption_key};

let key = derive_encryption_key(b"ikm", b"salt", b"context")?;

Hashing

use mtp_crypto::{sha256, sha256_double};

let h = sha256(b"data");
let h2 = sha256_double(b"data");

Key types

Type Secret Zeroized
EncryptionPrivateKey KEM/ECDH secret Yes
EncryptionPublicKey KEM/ECDH public No
SignaturePrivateKey Classical signing key Yes
SignaturePublicKey Classical verifying key No
KemPrivateKey Hybrid KEM secret Yes
KemPublicKey Hybrid KEM public No
SignaturePqPrivateKey PQC signing key Yes
SignaturePqPublicKey PQC verifying key No

KeyGroup holds classical keys; Keyring holds all six (hybrid KEM + PQ sig + classical sig).

Feature flags

[dependencies]
mtp-crypto = { path = "../crypto" }                          # classical
mtp-crypto = { path = "../crypto", features = ["pqc"] }       # post-quantum
mtp-crypto = { path = "../crypto", features = ["full", "pqc"] } # all