mtp/crypto
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Alois 6b9bbb6ebf
Some checks failed
CI / rustfmt (push) Successful in 17s
CI / wasm build (push) Successful in 1m18s
CI / clippy (push) Successful in 1m32s
CI / test (push) Successful in 1m53s
CI / example (push) Successful in 1m35s
CI / duplicate code (push) Failing after 31s
CI / web client (push) Failing after 32s
CI / cargo-machete (push) Successful in 1m9s
CI / cargo-deny (push) Failing after 2m31s
(feat): add crypto interface for MTPClient in wasm
(qol): update readme
(fix): small bug in keypair.rs
2026-06-28 16:04:03 +02:00
..
src (feat): add crypto interface for MTPClient in wasm 2026-06-28 16:04:03 +02:00
Cargo.lock Gitignores 2026-06-27 02:00:42 +02:00
Cargo.toml [Add] Key de-/serialization 2026-06-28 14:42:56 +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